From 4beb539c4eaa09068f48583e675d429969adb89a Mon Sep 17 00:00:00 2001 From: "@Someone" <45270312+Someone-193@users.noreply.github.com> Date: Fri, 24 Oct 2025 14:04:30 -0400 Subject: [PATCH 01/10] commit --- EXILED/Exiled.API/Features/Player.cs | 47 ++++++++++++ EXILED/Exiled.API/Structs/RoleData.cs | 76 +++++++++++++++++++ EXILED/Exiled.Events/Events.cs | 8 +- .../Exiled.Events/Handlers/Internal/Round.cs | 43 +++++++++++ 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 EXILED/Exiled.API/Structs/RoleData.cs diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index cba7d0864d..07f7d20ad0 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -127,6 +127,7 @@ public Player(GameObject gameObject) DictionaryPool.Pool.Return(SessionVariables); DictionaryPool.Pool.Return(FriendlyFireMultiplier); DictionaryPool>.Pool.Return(CustomRoleFriendlyFireMultiplier); + ListPool>.Pool.Return(FakeRoleGenerator); } /// @@ -407,6 +408,11 @@ public float InfoViewRange /// public Dictionary SessionVariables { get; } = DictionaryPool.Pool.Get(); + /// + /// Gets a dictionary that contains from this players POV, a dictionary containing other players and their faked roles with custom data. + /// + public Dictionary FakeRoles { get; } = new(); + /// /// Gets a value indicating whether the player has Do Not Track (DNT) enabled. If this value is , data about the player unrelated to server security shouldn't be stored. /// @@ -603,6 +609,12 @@ internal set } } + /// + /// Gets a of generating a to fake the others role whenever another player changes role. + /// + /// See for usage. + public List> FakeRoleGenerator { get; } = ListPool>.Pool.Get(); + /// /// Gets the role that player had before changing role. /// @@ -1835,6 +1847,41 @@ public void TrySetCustomRoleFriendlyFire(string roleTypeId, Dictionary Whether the item was able to be added. public bool TryRemoveCustomeRoleFriendlyFire(string role) => CustomRoleFriendlyFireMultiplier.Remove(role); + /// + /// Adds a from a to a that is used every time a players role changes. + /// + /// The function that determines if a players role will be faked (to a given viewer) after their role changes. + /// The first Func in that returns a RoleData that is not will be used for faking appearance. + public void SetAppearance(Func generator) + { + FakeRoleGenerator.Add(generator); + } + + /// + /// Fakes this players role to other viewers. + /// + /// The players to affect. + /// The fake role. + public void SetAppearance(IEnumerable viewers, RoleTypeId fakeRole) + { + foreach (Player player in viewers) + { + player.SetAppearance(this, fakeRole); + } + } + + /// + /// Fakes another players role to this player. + /// + /// The target. + /// The fake role. + /// The Unit ID of the player, if is an NTF role. + public void SetAppearance(Player player, RoleTypeId fakeRole, byte unitId = 0) + { + FakeRoles[player] = new RoleData(fakeRole, unitId); + player.ChangeAppearance(fakeRole, new[] { this }); + } + /// /// Forces the player's client to play the weapon reload animation, bypassing server-side checks. /// diff --git a/EXILED/Exiled.API/Structs/RoleData.cs b/EXILED/Exiled.API/Structs/RoleData.cs new file mode 100644 index 0000000000..7497b6d0a3 --- /dev/null +++ b/EXILED/Exiled.API/Structs/RoleData.cs @@ -0,0 +1,76 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Structs +{ + using System; + + using PlayerRoles; + + /// + /// A struct representing all data regarding a fake role. + /// + public struct RoleData : IEquatable + { + /// + /// Initializes a new instance of the struct. + /// + /// The fake role. + /// The fake UnitID, if is an NTF role. + public RoleData(RoleTypeId role = RoleTypeId.None, byte unitId = 0) + { + Role = role; + UnitId = unitId; + } + + /// + /// Gets the static representing no data. + /// + public static RoleData None { get; } = new(RoleTypeId.None); + + /// + /// Gets or sets the fake role. + /// + public RoleTypeId Role { get; set; } + + /// + /// Gets or sets the UnitID of the fake role, if is an NTF role. + /// + public byte UnitId { get; set; } + + /// + /// Checks if 2 are equal. + /// + /// A . + /// The other . + /// Whether the parameters are equal. + public static bool operator ==(RoleData left, RoleData right) => left.Equals(right); + + /// + /// Checks if 2 are not equal. + /// + /// A . + /// The other . + /// Whether the parameters are not equal. + public static bool operator !=(RoleData left, RoleData right) => !left.Equals(right); + + /// + public bool Equals(RoleData other) => Role == other.Role && UnitId == other.UnitId; + + /// + public override bool Equals(object obj) => obj is RoleData other && Equals(other); + + /// + public override int GetHashCode() + { + unchecked + { + return ((int)Role * 397) ^ UnitId.GetHashCode(); + } + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index 1645fe20a1..a1bdd040a2 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -18,9 +18,9 @@ namespace Exiled.Events using HarmonyLib; using InventorySystem.Items.Pickups; using InventorySystem.Items.Usables; + using PlayerRoles.FirstPersonControl.NetworkMessages; using PlayerRoles.Ragdolls; using PlayerRoles.RoleAssign; - using Respawning; using UnityEngine.SceneManagement; using UserSettings.ServerSpecific; @@ -68,6 +68,7 @@ public override void OnEnabled() Handlers.Server.RestartingRound += Handlers.Internal.Round.OnRestartingRound; Handlers.Server.RoundStarted += Handlers.Internal.Round.OnRoundStarted; Handlers.Player.ChangingRole += Handlers.Internal.Round.OnChangingRole; + Handlers.Player.Spawned += Handlers.Internal.Round.OnSpawned; Handlers.Player.SpawningRagdoll += Handlers.Internal.Round.OnSpawningRagdoll; Handlers.Scp049.ActivatingSense += Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified += Handlers.Internal.Round.OnVerified; @@ -92,6 +93,8 @@ public override void OnEnabled() LabApi.Events.Handlers.PlayerEvents.ReloadingWeapon += Handlers.Player.OnReloadingWeapon; LabApi.Events.Handlers.PlayerEvents.UnloadingWeapon += Handlers.Player.OnUnloadingWeapon; + FpcServerPositionDistributor.RoleSyncEvent += Handlers.Internal.Round.OnRoleSyncEvent; + ServerConsole.ReloadServerName(); } @@ -110,6 +113,7 @@ public override void OnDisabled() Handlers.Server.RestartingRound -= Handlers.Internal.Round.OnRestartingRound; Handlers.Server.RoundStarted -= Handlers.Internal.Round.OnRoundStarted; Handlers.Player.ChangingRole -= Handlers.Internal.Round.OnChangingRole; + Handlers.Player.Spawned -= Handlers.Internal.Round.OnSpawned; Handlers.Player.SpawningRagdoll -= Handlers.Internal.Round.OnSpawningRagdoll; Handlers.Scp049.ActivatingSense -= Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified -= Handlers.Internal.Round.OnVerified; @@ -129,6 +133,8 @@ public override void OnDisabled() LabApi.Events.Handlers.PlayerEvents.ReloadingWeapon -= Handlers.Player.OnReloadingWeapon; LabApi.Events.Handlers.PlayerEvents.UnloadingWeapon -= Handlers.Player.OnUnloadingWeapon; + + FpcServerPositionDistributor.RoleSyncEvent -= Handlers.Internal.Round.OnRoleSyncEvent; } /// diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 3ce8660bbe..99050276b3 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -7,6 +7,7 @@ namespace Exiled.Events.Handlers.Internal { + using System; using System.Collections.Generic; using System.Linq; @@ -28,6 +29,7 @@ namespace Exiled.Events.Handlers.Internal using InventorySystem.Items.Firearms.Attachments.Components; using InventorySystem.Items.Usables; using InventorySystem.Items.Usables.Scp244.Hypothermia; + using Mirror; using PlayerRoles; using PlayerRoles.FirstPersonControl; using PlayerRoles.RoleAssign; @@ -85,6 +87,23 @@ public static void OnChangingRole(ChangingRoleEventArgs ev) ev.Player.Inventory.ServerDropEverything(); } + /// + public static void OnSpawned(SpawnedEventArgs ev) + { + foreach (Player viewer in Player.Enumerable.Except(new[] { ev.Player })) + { + foreach (Func generator in viewer.FakeRoleGenerator) + { + RoleData data = generator(ev.Player); + if (data.Role != RoleTypeId.None) + { + viewer.FakeRoles[ev.Player] = data; + ev.Player.ChangeAppearance(data.Role, new[] { viewer }, false, data.UnitId); + } + } + } + } + /// public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { @@ -124,6 +143,30 @@ public static void OnVerified(VerifiedEventArgs ev) } } + /// + /// Makes fake role API work. + /// + /// The of the viewer. + /// The of the player. + /// The actual . + /// The pooled . + /// A role, fake if needed. + public static RoleTypeId OnRoleSyncEvent(ReferenceHub viewerHub, ReferenceHub ownerHub, RoleTypeId actualRole, NetworkWriter writer) + { + Player viewer = Player.Get(viewerHub); + Player owner = Player.Get(ownerHub); + + if (viewer.FakeRoles.TryGetValue(owner, out RoleData data)) + { + if (data.UnitId != 0) + writer.WriteByte(data.UnitId); + + return data.Role; + } + + return actualRole; + } + private static void GenerateAttachments() { foreach (FirearmType firearmType in EnumUtils.Values) From 395b43ce468c78960cba8792d6d4917d994ed4a6 Mon Sep 17 00:00:00 2001 From: "@Someone" <45270312+Someone-193@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:37:44 -0500 Subject: [PATCH 02/10] Some changes --- EXILED/Exiled.API/Features/Player.cs | 6 +++--- EXILED/Exiled.Events/Handlers/Internal/Round.cs | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 9567ac6a51..a61d640a84 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -1866,11 +1866,12 @@ public void SetAppearance(Func generator) /// /// The players to affect. /// The fake role. - public void SetAppearance(IEnumerable viewers, RoleTypeId fakeRole) + /// /// The Unit ID of the player, if is an NTF role. + public void SetAppearance(IEnumerable viewers, RoleTypeId fakeRole, byte unitId = 0) { foreach (Player player in viewers) { - player.SetAppearance(this, fakeRole); + player.SetAppearance(this, fakeRole, unitId); } } @@ -1883,7 +1884,6 @@ public void SetAppearance(IEnumerable viewers, RoleTypeId fakeRole) public void SetAppearance(Player player, RoleTypeId fakeRole, byte unitId = 0) { FakeRoles[player] = new RoleData(fakeRole, unitId); - player.ChangeAppearance(fakeRole, new[] { this }); } /// diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 99050276b3..4cedb7a21e 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -98,7 +98,6 @@ public static void OnSpawned(SpawnedEventArgs ev) if (data.Role != RoleTypeId.None) { viewer.FakeRoles[ev.Player] = data; - ev.Player.ChangeAppearance(data.Role, new[] { viewer }, false, data.UnitId); } } } @@ -137,9 +136,21 @@ public static void OnVerified(VerifiedEventArgs ev) } // Fix bug that player that Join do not receive information about other players Scale - foreach (Player player in ReferenceHub.AllHubs.Select(Player.Get)) + foreach (Player player in Player.Enumerable) { player.SetFakeScale(player.Scale, new List() { ev.Player }); + + if (player != ev.Player) + { + foreach (Func generator in player.FakeRoleGenerator) + { + RoleData data = generator(ev.Player); + if (data.Role != RoleTypeId.None) + { + ev.Player.FakeRoles[player] = data; + } + } + } } } From 2e7f2d353b3b2b529519324ea3088cc0319d33b3 Mon Sep 17 00:00:00 2001 From: "@Someone" <45270312+Someone-193@users.noreply.github.com> Date: Mon, 5 Jan 2026 13:34:28 -0500 Subject: [PATCH 03/10] merge dev --- EXILED/EXILED.props | 2 +- EXILED/Exiled.API/Enums/CameraType.cs | 5 + EXILED/Exiled.API/Enums/DoorType.cs | 5 + EXILED/Exiled.API/Enums/EffectType.cs | 57 ++-- EXILED/Exiled.API/Enums/GlassType.cs | 5 + EXILED/Exiled.API/Enums/PrefabType.cs | 42 +++ EXILED/Exiled.API/Enums/ProjectileType.cs | 6 +- EXILED/Exiled.API/Enums/RoomType.cs | 5 + EXILED/Exiled.API/Enums/Side.cs | 5 + EXILED/Exiled.API/Exiled.API.csproj | 1 + .../Extensions/DamageTypeExtensions.cs | 7 + .../Extensions/EffectTypeExtension.cs | 3 + .../Exiled.API/Extensions/MirrorExtensions.cs | 33 +-- .../Exiled.API/Extensions/RoleExtensions.cs | 9 +- EXILED/Exiled.API/Features/Camera.cs | 5 + EXILED/Exiled.API/Features/Cassie.cs | 116 +++++--- .../DamageHandlers/CustomDamageHandler.cs | 12 +- .../DamageHandlers/DamageHandlerBase.cs | 7 + EXILED/Exiled.API/Features/Doors/Door.cs | 1 + EXILED/Exiled.API/Features/Effect.cs | 2 +- .../Features/Items/FirearmModules/Magazine.cs | 9 +- .../FirearmModules/Primary/Scp127Magazine.cs | 80 +++++ EXILED/Exiled.API/Features/Items/Item.cs | 15 +- EXILED/Exiled.API/Features/Items/Jailbird.cs | 26 +- .../Features/Items/Keycards/ChaosKeycard.cs | 3 +- .../Exiled.API/Features/Items/Marshmallow.cs | 102 +++++++ EXILED/Exiled.API/Features/Items/Scp127.cs | 274 ++++++++++++++++++ EXILED/Exiled.API/Features/Lift.cs | 7 + .../Features/Pickups/JailbirdPickup.cs | 10 +- .../Features/Pickups/Scp1509Pickup.cs | 2 +- EXILED/Exiled.API/Features/Player.cs | 54 +++- EXILED/Exiled.API/Features/Recontainer.cs | 16 +- EXILED/Exiled.API/Features/Roles/FpcRole.cs | 24 ++ .../Exiled.API/Features/Roles/Scp049Role.cs | 3 +- .../Exiled.API/Features/Roles/Scp096Role.cs | 18 +- .../Exiled.API/Features/Roles/Scp1507Role.cs | 2 +- EXILED/Exiled.API/Features/Room.cs | 1 + EXILED/Exiled.API/Features/Scp559.cs | 24 +- EXILED/Exiled.API/Features/Server.cs | 22 +- EXILED/Exiled.API/Features/Waves/TimedWave.cs | 4 +- EXILED/Exiled.API/Features/Window.cs | 1 + .../API/Features/CustomItem.cs | 9 - .../API/Features/CustomRole.cs | 6 + EXILED/Exiled.CustomRoles/Commands/Get.cs | 123 ++++++++ EXILED/Exiled.CustomRoles/Commands/Give.cs | 2 +- EXILED/Exiled.CustomRoles/Commands/Parent.cs | 3 +- .../Exiled.CustomRoles.csproj | 2 +- EXILED/Exiled.Events/Commands/TpsCommand.cs | 5 +- .../Cassie/SendingCassieMessageEventArgs.cs | 144 +++++++-- .../EventArgs/Interfaces/IMarshmallowEvent.cs | 22 ++ .../EventArgs/Interfaces/IScp127Event.cs | 20 ++ .../EventArgs/Interfaces/IScp1507Event.cs | 2 +- .../EventArgs/Interfaces/IScp559Event.cs | 2 +- .../EventArgs/Item/CacklingEventArgs.cs | 50 ++++ .../EventArgs/Item/PunchingEventArgs.cs | 50 ++++ .../Map/AnnouncingScpTerminationEventArgs.cs | 18 +- .../Player/ReceivingEffectEventArgs.cs | 21 +- .../Scp1576TransmissionEndedEventArgs.cs | 41 +++ .../EventArgs/Player/UsedItemEventArgs.cs | 14 +- .../Scp127/GainedExperienceEventArgs.cs | 51 ++++ .../Scp127/GainingExperienceEventArgs.cs | 59 ++++ .../EventArgs/Scp127/TalkedEventArgs.cs | 52 ++++ .../EventArgs/Scp127/TalkingEventArgs.cs | 57 ++++ .../Scp1507/AttackingDoorEventArgs.cs | 2 +- .../EventArgs/Scp1507/ScreamingEventArgs.cs | 2 +- .../Scp1507/SpawningFlamingosEventArgs.cs | 2 +- .../EventArgs/Scp1507/UsingTapeEventArgs.cs | 2 +- .../Scp2536/FoundPositionEventArgs.cs | 40 +++ .../Scp559/InteractingScp559EventArgs.cs | 7 +- .../EventArgs/Scp559/SpawningEventArgs.cs | 2 +- EXILED/Exiled.Events/Events.cs | 12 + .../Exiled.Events/Handlers/Internal/Round.cs | 15 +- EXILED/Exiled.Events/Handlers/Item.cs | 22 ++ EXILED/Exiled.Events/Handlers/Player.cs | 11 + EXILED/Exiled.Events/Handlers/Scp127.cs | 81 ++++++ EXILED/Exiled.Events/Handlers/Scp1507.cs | 2 +- EXILED/Exiled.Events/Handlers/Scp2536.cs | 11 + EXILED/Exiled.Events/Handlers/Scp559.cs | 2 +- .../Events/Cassie/SendingCassieMessage.cs | 54 +--- .../Patches/Events/Item/Cackling.cs | 65 +++++ .../Patches/Events/Item/Punching.cs | 65 +++++ .../Events/Map/AnnouncingChaosEntrance.cs | 11 +- .../Events/Map/AnnouncingNtfEntrance.cs | 25 +- .../Events/Map/AnnouncingNtfMiniEntrance.cs | 12 +- .../Events/Map/AnnouncingScpTermination.cs | 108 ++++--- .../Events/Map/AnnouncingTeamEntrance.cs | 68 ----- .../Events/Map/SpawningRoomConnector.cs | 13 +- .../Patches/Events/Player/Landing.cs | 16 +- .../Events/Player/ReceivingStatusEffect.cs | 12 +- .../Events/Player/Scp1576TransmissionEnded.cs | 59 ++++ .../Events/Player/UsedItemByHolstering.cs | 58 ++++ .../Patches/Events/Scp079/Recontaining.cs | 7 +- .../Patches/Events/Scp2536/FoundPosition.cs | 86 ++++++ .../Patches/Events/Scp2536/GrantingGift.cs | 44 ++- .../Patches/Events/Scp559/Interacting.cs | 15 +- .../Patches/Events/Scp559/Spawning.cs | 2 + .../Events/Scp914/InteractingEvents.cs | 8 +- .../Patches/Fixes/FixEffectOrder.cs | 101 +++++++ .../Patches/Fixes/FixMarshmallowManFF.cs | 91 ++++++ .../Patches/Fixes/FixNWFlashbangDuration.cs | 30 ++ .../Patches/Fixes/FixScp1507DestroyingDoor.cs | 52 ++++ .../Patches/Fixes/Jailbird914CoarseFix.cs | 2 +- .../Patches/Fixes/JailbirdHitRegFix.cs | 61 ---- .../Patches/Generic/IndividualFriendlyFire.cs | 7 + .../Patches/Generic/Scp127MaxHs.cs | 32 ++ EXILED/Exiled.Installer/Program.cs | 2 +- EXILED/Exiled.Loader/AutoUpdateFiles.cs | 2 +- EXILED/Exiled.Loader/ConfigManager.cs | 5 +- EXILED/Exiled.Loader/Loader.cs | 3 + EXILED/Exiled.Loader/Updater.cs | 2 +- .../SCPSLRessources/NW_Documentation.md | 91 ++++-- 111 files changed, 2676 insertions(+), 524 deletions(-) create mode 100644 EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs create mode 100644 EXILED/Exiled.API/Features/Items/Marshmallow.cs create mode 100644 EXILED/Exiled.API/Features/Items/Scp127.cs create mode 100644 EXILED/Exiled.CustomRoles/Commands/Get.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs create mode 100644 EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs create mode 100644 EXILED/Exiled.Events/Handlers/Scp127.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Item/Punching.cs delete mode 100644 EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Player/Scp1576TransmissionEnded.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Player/UsedItemByHolstering.cs create mode 100644 EXILED/Exiled.Events/Patches/Events/Scp2536/FoundPosition.cs create mode 100644 EXILED/Exiled.Events/Patches/Fixes/FixEffectOrder.cs create mode 100644 EXILED/Exiled.Events/Patches/Fixes/FixMarshmallowManFF.cs create mode 100644 EXILED/Exiled.Events/Patches/Fixes/FixNWFlashbangDuration.cs create mode 100644 EXILED/Exiled.Events/Patches/Fixes/FixScp1507DestroyingDoor.cs delete mode 100644 EXILED/Exiled.Events/Patches/Fixes/JailbirdHitRegFix.cs create mode 100644 EXILED/Exiled.Events/Patches/Generic/Scp127MaxHs.cs diff --git a/EXILED/EXILED.props b/EXILED/EXILED.props index f67ef6f8da..edc17d4fb2 100644 --- a/EXILED/EXILED.props +++ b/EXILED/EXILED.props @@ -15,7 +15,7 @@ - 9.10.1 + 9.12.2 false diff --git a/EXILED/Exiled.API/Enums/CameraType.cs b/EXILED/Exiled.API/Enums/CameraType.cs index 535e7366ce..292da90b2d 100644 --- a/EXILED/Exiled.API/Enums/CameraType.cs +++ b/EXILED/Exiled.API/Enums/CameraType.cs @@ -159,6 +159,11 @@ public enum CameraType EzGateAElevators, EzGateBInterior, EzGateBSide, + EzGateAStairwell, + EzGateAUpper, + HczLoadingBay, + HczLoadingBayRamp, + HczLoadingBayStairwell, #endregion } } diff --git a/EXILED/Exiled.API/Enums/DoorType.cs b/EXILED/Exiled.API/Enums/DoorType.cs index 87e0de99a5..5863d6e79a 100644 --- a/EXILED/Exiled.API/Enums/DoorType.cs +++ b/EXILED/Exiled.API/Enums/DoorType.cs @@ -369,5 +369,10 @@ public enum DoorType /// Represents the door in the Armory. /// GateAArmory, + + /// + /// Represents the door in . + /// + HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/EffectType.cs b/EXILED/Exiled.API/Enums/EffectType.cs index e70e273e77..9bed0519c9 100644 --- a/EXILED/Exiled.API/Enums/EffectType.cs +++ b/EXILED/Exiled.API/Enums/EffectType.cs @@ -216,7 +216,7 @@ public enum EffectType /// /// Makes you a marshmallow guy. /// - [Obsolete("Not functional in-game")] + // [Obsolete("Not functional in-game")] Marshmallow, /// @@ -261,27 +261,27 @@ public enum EffectType Blurred, /// - /// Makes you a flamingo. + /// Makes you a flamingo . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] BecomingFlamingo, /// - /// Makes you a Child after eating Cake. + /// Makes you a Child after eating Cake . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] Scp559, /// - /// Scp956 found you. + /// Scp956 found you . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] Scp956Target, /// - /// you are snowed. + /// you are snowed . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] Snowed, /// @@ -317,78 +317,93 @@ public enum EffectType /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] Metal, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] OrangeCandy, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] OrangeWitness, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] Prismatic, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] SlowMetabolism, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] Spicy, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween or Christmas.")] SugarCrave, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] SugarHigh, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] SugarRush, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] TemporaryBypass, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] TraumatizedByEvil, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] WhiteCandy, /// /// . /// Scp1509Resurrected, + + /// + /// . + /// + FocusedVision, + + /// + /// . + /// + AnomalousRegeneration, + + /// + /// . + /// + AnomalousTarget, } } diff --git a/EXILED/Exiled.API/Enums/GlassType.cs b/EXILED/Exiled.API/Enums/GlassType.cs index 85c068108f..fef4d59f44 100644 --- a/EXILED/Exiled.API/Enums/GlassType.cs +++ b/EXILED/Exiled.API/Enums/GlassType.cs @@ -84,5 +84,10 @@ public enum GlassType /// Represents the window in . /// GateAArmory, + + /// + /// Represents the window in + /// + HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/PrefabType.cs b/EXILED/Exiled.API/Enums/PrefabType.cs index 6a52ce7995..43936f1d80 100644 --- a/EXILED/Exiled.API/Enums/PrefabType.cs +++ b/EXILED/Exiled.API/Enums/PrefabType.cs @@ -417,5 +417,47 @@ public enum PrefabType [Prefab(213466224, "SCP-939 Ragdoll Halloween")] Scp939RagdollHalloween, + + [Prefab(689741320, "SCP-559 Cake")] + Scp559Cake, + + [Prefab(2657863153, "SCP-956")] + Scp956, + + [Prefab(1205960739, "SCP-2536 Tree")] + Scp2536, + + [Prefab(2102014206, "Snowpile")] + Snowpile, + + [Prefab(3401975113, "Scp018Projectile Christmas")] + Scp018ProjectileChristmas, + + [Prefab(3223468476, "SnowballProjectile")] + SnowballProjectile, + + [Prefab(296717882, "CoalPickup")] + CoalPickup, + + [Prefab(409273101, "TapePlayerPickup")] + Scp1507TapePickup, + + [Prefab(3971391978, "Scp021JPickup")] + Scp021JPickup, + + [Prefab(142820664, "CoalProjectile")] + CoalProjectile, + + [Prefab(2405470903, "Scp2536Projectile")] + Scp2536Projectile, + + [Prefab(1496232901, "SCP-173 Ragdoll Variant")] + Scp173RagdollChristmas, + + [Prefab(6069361, "SnowPoop - TantrumObj")] + SnowTantrum, + + [Prefab(3654754970, "SCP-1507 Ragdoll")] + Scp1507Ragdoll, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/ProjectileType.cs b/EXILED/Exiled.API/Enums/ProjectileType.cs index a8072ed48e..2d95210924 100644 --- a/EXILED/Exiled.API/Enums/ProjectileType.cs +++ b/EXILED/Exiled.API/Enums/ProjectileType.cs @@ -51,21 +51,21 @@ public enum ProjectileType /// Coal. /// Used by . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] Coal, /// /// SpecialCoal. /// Used by . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] SpecialCoal, /// /// Snowball. /// Used by . /// - [Obsolete("Only availaible for Christmas.")] + // [Obsolete("Only availaible for Christmas.")] Snowball, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/RoomType.cs b/EXILED/Exiled.API/Enums/RoomType.cs index 0b7737c193..6dceeea6e2 100644 --- a/EXILED/Exiled.API/Enums/RoomType.cs +++ b/EXILED/Exiled.API/Enums/RoomType.cs @@ -353,5 +353,10 @@ public enum RoomType /// Heavy Containment Zone's straight hall room with lava. /// HczDss12 = HczIncineratorWayside, + + /// + /// Heavy Containment Zone's T-intersection with a ramp in it. + /// + HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/Side.cs b/EXILED/Exiled.API/Enums/Side.cs index 5e9c063be7..5accace2f3 100644 --- a/EXILED/Exiled.API/Enums/Side.cs +++ b/EXILED/Exiled.API/Enums/Side.cs @@ -52,5 +52,10 @@ public enum Side /// No team. Same as . /// None, + + /// + /// Contains and . Same as . + /// + Flamingos, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Exiled.API.csproj b/EXILED/Exiled.API/Exiled.API.csproj index 31fe36e002..70f81bf0d1 100644 --- a/EXILED/Exiled.API/Exiled.API.csproj +++ b/EXILED/Exiled.API/Exiled.API.csproj @@ -34,6 +34,7 @@ + diff --git a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs index 95dfc33727..6fde63477d 100644 --- a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs +++ b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs @@ -204,6 +204,13 @@ public static DamageType GetDamageType(DamageHandlerBase damageHandlerBase) Log.Warn($"{nameof(DamageTypeExtensions)}.{nameof(damageHandlerBase)}: No matching {nameof(DamageType)} for {nameof(UniversalDamageHandler)} with ID {translation.Id}, type will be reported as {DamageType.Unknown}. Report this to EXILED Devs."); return DamageType.Unknown; } + + case AttackerDamageHandler attackerDamageHandler: + { + if (Player.TryGet(attackerDamageHandler.Attacker, out Player attacker) && attacker.CurrentItem?.Type == ItemType.MarshmallowItem) + return DamageType.Marshmallow; + return DamageType.Unknown; + } } return DamageType.Unknown; diff --git a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs index c44a32362d..088438e085 100644 --- a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs +++ b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs @@ -101,6 +101,9 @@ public static class EffectTypeExtension { EffectType.TraumatizedByEvil, typeof(TraumatizedByEvil) }, { EffectType.WhiteCandy, typeof(WhiteCandy) }, { EffectType.Scp1509Resurrected, typeof(Scp1509Resurrected) }, + { EffectType.FocusedVision, typeof(FocusedVision) }, + { EffectType.AnomalousRegeneration, typeof(AnomalousRegeneration) }, + { EffectType.AnomalousTarget, typeof(AnomalousTarget) }, #pragma warning restore CS0618 }); diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs index 605e6466c0..3ba47fd9a8 100644 --- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs +++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs @@ -17,6 +17,7 @@ namespace Exiled.API.Extensions using AdminToys; using AudioPooling; + using Cassie; using CustomPlayerEffects; using Exiled.API.Enums; using Exiled.API.Features.Items; @@ -512,13 +513,12 @@ public static void ResyncKeycardPickup(CustomKeycardPickup customKeycard) /// Same on 's isSubtitles. public static void PlayCassieAnnouncement(this Player player, string words, bool makeHold = false, bool makeNoise = true, bool isSubtitles = false) { - foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) - { - if (controller != null) - { - SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), words, makeHold, makeNoise, isSubtitles); - } - } + CassieAnnouncement announcement = new(new CassieTtsPayload(words, isSubtitles, makeHold), 0, makeNoise ? 1 : 0); + + // processes makeNoise + announcement.OnStartedPlaying(); + + announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); } /// @@ -533,23 +533,12 @@ public static void PlayCassieAnnouncement(this Player player, string words, bool /// Same on 's isSubtitles. public static void MessageTranslated(this Player player, string words, string translation, string customSubtitles, bool makeHold = false, bool makeNoise = true, bool isSubtitles = true) { - StringBuilder announcement = StringBuilderPool.Pool.Get(); + CassieAnnouncement announcement = new(new CassieTtsPayload(words, customSubtitles, makeHold), 0, makeNoise ? 1 : 0); - string[] cassies = words.Split('\n'); - string[] translations = translation.Split('\n'); + // processes makeNoise + announcement.OnStartedPlaying(); - for (int i = 0; i < cassies.Length; i++) - announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); - - string message = StringBuilderPool.Pool.ToStringReturn(announcement); - - foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) - { - if (controller != null) - { - SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), message, makeHold, makeNoise, isSubtitles, customSubtitles); - } - } + announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); } /// diff --git a/EXILED/Exiled.API/Extensions/RoleExtensions.cs b/EXILED/Exiled.API/Extensions/RoleExtensions.cs index 369910654a..db1a7c99a9 100644 --- a/EXILED/Exiled.API/Extensions/RoleExtensions.cs +++ b/EXILED/Exiled.API/Extensions/RoleExtensions.cs @@ -70,6 +70,7 @@ public static class RoleExtensions Team.FoundationForces or Team.Scientists => Side.Mtf, Team.ChaosInsurgency or Team.ClassD => Side.ChaosInsurgency, Team.OtherAlive => Side.Tutorial, + Team.Flamingos => Side.Flamingos, _ => Side.None, }; @@ -80,12 +81,13 @@ public static class RoleExtensions /// . public static Team GetTeam(this RoleTypeId roleType) => roleType switch { - RoleTypeId.ChaosConscript or RoleTypeId.ChaosMarauder or RoleTypeId.ChaosRepressor or RoleTypeId.ChaosRifleman => Team.ChaosInsurgency, + RoleTypeId.ChaosConscript or RoleTypeId.ChaosMarauder or RoleTypeId.ChaosRepressor or RoleTypeId.ChaosRifleman or RoleTypeId.ChaosFlamingo => Team.ChaosInsurgency, RoleTypeId.Scientist => Team.Scientists, RoleTypeId.ClassD => Team.ClassD, - RoleTypeId.Scp049 or RoleTypeId.Scp939 or RoleTypeId.Scp0492 or RoleTypeId.Scp079 or RoleTypeId.Scp096 or RoleTypeId.Scp106 or RoleTypeId.Scp173 or RoleTypeId.Scp3114 => Team.SCPs, - RoleTypeId.FacilityGuard or RoleTypeId.NtfCaptain or RoleTypeId.NtfPrivate or RoleTypeId.NtfSergeant or RoleTypeId.NtfSpecialist => Team.FoundationForces, + RoleTypeId.Scp049 or RoleTypeId.Scp939 or RoleTypeId.Scp0492 or RoleTypeId.Scp079 or RoleTypeId.Scp096 or RoleTypeId.Scp106 or RoleTypeId.Scp173 or RoleTypeId.Scp3114 or RoleTypeId.ZombieFlamingo=> Team.SCPs, + RoleTypeId.FacilityGuard or RoleTypeId.NtfCaptain or RoleTypeId.NtfPrivate or RoleTypeId.NtfSergeant or RoleTypeId.NtfSpecialist or RoleTypeId.NtfFlamingo => Team.FoundationForces, RoleTypeId.Tutorial => Team.OtherAlive, + RoleTypeId.Flamingo or RoleTypeId.AlphaFlamingo => Team.Flamingos, _ => Team.Dead, }; @@ -131,6 +133,7 @@ public static bool TryGetRoleBase(this RoleTypeId roleType, out T roleBase) Team.ClassD or Team.ChaosInsurgency => LeadingTeam.ChaosInsurgency, Team.FoundationForces or Team.Scientists => LeadingTeam.FacilityForces, Team.SCPs => LeadingTeam.Anomalies, + Team.Flamingos => LeadingTeam.Flamingo, _ => LeadingTeam.Draw, }; diff --git a/EXILED/Exiled.API/Features/Camera.cs b/EXILED/Exiled.API/Features/Camera.cs index fca5cbbc73..fa17a77540 100644 --- a/EXILED/Exiled.API/Features/Camera.cs +++ b/EXILED/Exiled.API/Features/Camera.cs @@ -143,6 +143,11 @@ public class Camera : IWrapper, IWorldSpace ["GATE A ELEVATORS"] = CameraType.EzGateAElevators, ["GATE B INTERIOR"] = CameraType.EzGateBInterior, ["GATE B SIDE"] = CameraType.EzGateBSide, + ["GATE A STAIRWELL"] = CameraType.EzGateAStairwell, + ["GATE A UPPER"] = CameraType.EzGateAUpper, + ["LOADING BAY"] = CameraType.HczLoadingBay, + ["HCZ LOADING RAMP"] = CameraType.HczLoadingBayRamp, + ["STAIRWELL"] = CameraType.HczLoadingBayStairwell, // CustomCamera ["EZ ARM CAMERA TOY"] = CameraType.EzArmCameraToy, diff --git a/EXILED/Exiled.API/Features/Cassie.cs b/EXILED/Exiled.API/Features/Cassie.cs index 0730f9a5a9..475e68ad4e 100644 --- a/EXILED/Exiled.API/Features/Cassie.cs +++ b/EXILED/Exiled.API/Features/Cassie.cs @@ -7,19 +7,19 @@ namespace Exiled.API.Features { + using System; using System.Collections.Generic; using System.Linq; using System.Text; using Exiled.API.Features.Pools; - + using global::Cassie; + using global::Cassie.Interpreters; using MEC; - using PlayerRoles; - using PlayerStatsSystem; - using Respawning; + using Respawning.NamingRules; using CustomFirearmHandler = DamageHandlers.FirearmDamageHandler; using CustomHandlerBase = DamageHandlers.DamageHandlerBase; @@ -29,20 +29,15 @@ namespace Exiled.API.Features /// public static class Cassie { - /// - /// Gets the singleton. - /// - public static NineTailedFoxAnnouncer Announcer => NineTailedFoxAnnouncer.singleton; - /// /// Gets a value indicating whether C.A.S.S.I.E is currently announcing. Does not include decontamination or Alpha Warhead Messages. /// - public static bool IsSpeaking => Announcer.queue.Count != 0; + public static bool IsSpeaking => CassieAnnouncementDispatcher.AllAnnouncements.Count != 0; /// - /// Gets a of objects that C.A.S.S.I.E recognizes. + /// Gets a of objects that C.A.S.S.I.E recognizes. /// - public static IReadOnlyCollection VoiceLines => Announcer.voiceLines; + public static IReadOnlyCollection VoiceLines => CassieAnnouncementDispatcher.AllAnnouncements; /// /// Reproduce a non-glitched C.A.S.S.I.E message. @@ -52,7 +47,7 @@ public static class Cassie /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void Message(string message, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles); + new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); /// /// Reproduce a non-glitched C.A.S.S.I.E message with a possibility to custom the subtitles. @@ -64,14 +59,7 @@ public static void Message(string message, bool isHeld = false, bool isNoisy = t /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void MessageTranslated(string message, string translation, bool isHeld = false, bool isNoisy = true, bool isSubtitles = true) { - StringBuilder announcement = StringBuilderPool.Pool.Get(); - string[] cassies = message.Split('\n'); - string[] translations = translation.Split('\n'); - for (int i = 0; i < cassies.Length; i++) - announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); - - RespawnEffectsController.PlayCassieAnnouncement(announcement.ToString(), isHeld, isNoisy, isSubtitles); - StringBuilderPool.Pool.Return(announcement); + new CassieAnnouncement(new CassieTtsPayload(message, translation, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); } /// @@ -81,7 +69,7 @@ public static void MessageTranslated(string message, string translation, bool is /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void GlitchyMessage(string message, float glitchChance, float jamChance) => - Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance); + new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue(); /// /// Reproduce a non-glitched C.A.S.S.I.E message after a certain amount of seconds. @@ -92,7 +80,7 @@ public static void GlitchyMessage(string message, float glitchChance, float jamC /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void DelayedMessage(string message, float delay, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - Timing.CallDelayed(delay, () => RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles)); + Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue()); /// /// Reproduce a glitchy C.A.S.S.I.E announcement after a certain period of seconds. @@ -102,17 +90,53 @@ public static void DelayedMessage(string message, float delay, bool isHeld = fal /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void DelayedGlitchyMessage(string message, float delay, float glitchChance, float jamChance) => - Timing.CallDelayed(delay, () => Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance)); + Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue()); + + /// + /// Calculates the duration of a C.A.S.S.I.E message. + /// + /// The message, which duration will be calculated. + /// An obsolete parameter. + /// Another obsolete parameter. + /// Duration (in seconds) of specified message. + [Obsolete("Please use CalculateDuration(string)", true)] + public static float CalculateDuration(string message, bool obsolete1, float obsolete2) => CalculateDuration(message); /// /// Calculates the duration of a C.A.S.S.I.E message. /// /// The message, which duration will be calculated. - /// Determines if a number won't be converted to its full pronunciation. - /// The speed of the message. /// Duration (in seconds) of specified message. - public static float CalculateDuration(string message, bool rawNumber = false, float speed = 1f) - => Announcer.CalculateDuration(message, rawNumber, speed); + public static float CalculateDuration(string message) + { + if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) + { + return 0; + } + + float value = 0; + string[] lines = message.Split(' ', StringSplitOptions.RemoveEmptyEntries); + + CassiePlaybackModifiers modifiers = new(); + StringBuilder builder = StringBuilderPool.Pool.Get(); + + for (int i = 0; i < lines.Length; i++) + { + foreach (CassieInterpreter interpreter in CassieTtsAnnouncer.Interpreters) + { + bool halt; + foreach (CassieInterpreter.Result result in interpreter.GetResults(cassieLineDatabase, ref modifiers, lines[i], builder, out halt)) + { + value += (float)result.Modifiers.GetTimeUntilNextWord(result.Line); + } + + if (halt) + break; + } + } + + return value; + } /// /// Converts a into a Cassie-Readable CONTAINMENTUNIT. @@ -120,8 +144,16 @@ public static float CalculateDuration(string message, bool rawNumber = false, fl /// . /// Unit Name. /// Containment Unit text. - public static string ConvertTeam(Team team, string unitName) - => NineTailedFoxAnnouncer.ConvertTeam(team, unitName); + public static string ConvertTeam(Team team, string unitName) => team switch + { + Team.FoundationForces when NamingRulesManager.TryGetNamingRule(team, out UnitNamingRule unitNamingRule) => "CONTAINMENTUNIT " + unitNamingRule.TranslateToCassie(unitName), + Team.FoundationForces => "CONTAINMENTUNIT UNKNOWN", + Team.ChaosInsurgency => "BY CHAOSINSURGENCY", + Team.Scientists => "BY SCIENCE PERSONNEL", + Team.ClassD => "BY CLASSD PERSONNEL", + Team.Flamingos => "BY SCP 1 5 0 7", + _ => "UNKNOWN", + }; /// /// Converts a number into a Cassie-Readable String. @@ -129,7 +161,23 @@ public static string ConvertTeam(Team team, string unitName) /// Number to convert. /// A CASSIE-readable representing the number. public static string ConvertNumber(int num) - => NineTailedFoxAnnouncer.ConvertNumber(num); + { + if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) + { + return string.Empty; + } + + NumberInterpreter numberInterpreter = (NumberInterpreter)CassieTtsAnnouncer.Interpreters.FirstOrDefault((CassieInterpreter x) => x is NumberInterpreter); + if (numberInterpreter == null) + { + return string.Empty; + } + + CassiePlaybackModifiers cassiePlaybackModifiers = default; + StringBuilder stringBuilder = new(); + numberInterpreter.GetResults(cassieLineDatabase, ref cassiePlaybackModifiers, num.ToString(), stringBuilder, out bool flag); + return stringBuilder.ToString(); + } /// /// Announce a SCP Termination. @@ -137,7 +185,7 @@ public static string ConvertNumber(int num) /// SCP to announce termination of. /// HitInformation. public static void ScpTermination(Player scp, DamageHandlerBase info) - => NineTailedFoxAnnouncer.AnnounceScpTermination(scp.ReferenceHub, info); + => CassieScpTerminationAnnouncement.AnnounceScpTermination(scp.ReferenceHub, info); /// /// Announces the termination of a custom SCP name. @@ -167,14 +215,14 @@ public static void CustomScpTermination(string scpName, CustomHandlerBase info) /// /// Clears the C.A.S.S.I.E queue. /// - public static void Clear() => RespawnEffectsController.ClearQueue(); + public static void Clear() => CassieAnnouncementDispatcher.ClearAll(); /// /// Gets a value indicating whether the given word is a valid C.A.S.S.I.E word. /// /// The word to check. /// if the word is valid; otherwise, . - public static bool IsValid(string word) => Announcer.voiceLines.Any(line => line.apiName.ToUpper() == word.ToUpper()); + public static bool IsValid(string word) => CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase) ? cassieLineDatabase.AllLines.Any(line => line.ApiName.ToUpper() == word.ToUpper()) : false; /// /// Gets a value indicating whether the given sentence is all valid C.A.S.S.I.E word. diff --git a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs index 67b464474f..fde6e9e00a 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs @@ -39,11 +39,17 @@ public CustomDamageHandler(Player target, BaseHandler baseHandler) if (Attacker is not null) { if (baseHandler is BaseScpDamageHandler) + { CustomBase = new ScpDamageHandler(target, baseHandler); - else if (Attacker.CurrentItem is not null && Attacker.CurrentItem.Type.IsWeapon() && baseHandler is BaseFirearmHandler) - CustomBase = new FirearmDamageHandler(Attacker.CurrentItem, target, baseHandler); + } else - CustomBase = new DamageHandler(target, Attacker); + { + Item item = Attacker.CurrentItem; + if (item is not null && item.Type.IsWeapon() && baseHandler is BaseFirearmHandler) + CustomBase = new FirearmDamageHandler(item, target, baseHandler); + else + CustomBase = new DamageHandler(target, Attacker); + } } else { diff --git a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs index ec59d5ee5a..248e89452b 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs @@ -271,6 +271,13 @@ protected DamageType GetDamageType(BaseHandler damageHandler = null) FirearmType.FRMG0 => DamageType.Frmg0, _ => DamageType.Firearm }; + + case PlayerStatsSystem.AttackerDamageHandler attackerDamageHandler: + { + if (Player.TryGet(attackerDamageHandler.Attacker, out Player attacker) && attacker.CurrentItem?.Type == ItemType.MarshmallowItem) + return DamageType.Marshmallow; + return DamageType.Unknown; + } } return DamageType.Unknown; diff --git a/EXILED/Exiled.API/Features/Doors/Door.cs b/EXILED/Exiled.API/Features/Doors/Door.cs index 19718900a7..a8163f207c 100644 --- a/EXILED/Exiled.API/Features/Doors/Door.cs +++ b/EXILED/Exiled.API/Features/Doors/Door.cs @@ -624,6 +624,7 @@ private DoorType GetDoorType() RoomType.HczEzCheckpointA => DoorType.CheckpointArmoryA, RoomType.HczEzCheckpointB => DoorType.CheckpointArmoryB, RoomType.EzGateA => DoorType.GateAArmory, + RoomType.HczLoadingBay => DoorType.HczLoadingBay, _ => DoorType.UnknownDoor, }, "Unsecured Pryable GateDoor" => Room?.Type switch diff --git a/EXILED/Exiled.API/Features/Effect.cs b/EXILED/Exiled.API/Features/Effect.cs index f901966917..426b68dcdc 100644 --- a/EXILED/Exiled.API/Features/Effect.cs +++ b/EXILED/Exiled.API/Features/Effect.cs @@ -35,7 +35,7 @@ public Effect(StatusEffectBase statusEffectBase) if (!statusEffectBase.TryGetEffectType(out EffectType effect)) Log.Error($"EffectType not found please report to Exiled BugReport : {statusEffectBase}"); Type = effect; - Duration = statusEffectBase.Duration; + Duration = statusEffectBase.TimeLeft; Intensity = statusEffectBase.Intensity; IsEnabled = statusEffectBase.IsEnabled; } diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs index 50a2538c64..8fb2688bb7 100644 --- a/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs @@ -11,9 +11,8 @@ namespace Exiled.API.Features.Items.FirearmModules using Exiled.API.Features.Items.FirearmModules.Barrel; using Exiled.API.Features.Items.FirearmModules.Primary; - using InventorySystem.Items.Firearms.Modules; - + using InventorySystem.Items.Firearms.Modules.Scp127; using UnityEngine; /// @@ -66,8 +65,12 @@ public static Magazine Get(IAmmoContainerModule module) PumpActionModule pump => new PumpBarrelMagazine(pump), IPrimaryAmmoContainerModule primary => primary switch { - MagazineModule magazine => new NormalMagazine(magazine), CylinderAmmoModule cylinder => new CylinderMagazine(cylinder), + MagazineModule magazine => magazine switch + { + Scp127MagazineModule scp127MagazineModule => new Scp127Magazine(scp127MagazineModule), + _ => new NormalMagazine(magazine) + }, _ => null, }, _ => null, diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs new file mode 100644 index 0000000000..c3226169ea --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs @@ -0,0 +1,80 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items.FirearmModules.Primary +{ + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Represents a normal magazine for SCP-127. + /// + public class Scp127Magazine : NormalMagazine + { + /// + /// Initializes a new instance of the class. + /// + /// + public Scp127Magazine(Scp127MagazineModule magazine) + : base(magazine) + { + MagazineModule = magazine; + } + + /// + public new Scp127MagazineModule MagazineModule { get; } + + /// + /// Gets or sets the kill bonus. + /// + public int KillBonus + { + get => MagazineModule.KillBonus; + set => MagazineModule.KillBonus = value; + } + + /// + /// Gets or sets the rank up bonus. + /// + public int RankUpBonus + { + get => MagazineModule.RankUpBonus; + set => MagazineModule.RankUpBonus = value; + } + + /// + /// Gets or sets all settings. + /// + public Scp127MagazineModule.RegenerationSettings[] RegenerationPerTier + { + get => MagazineModule._regenerationPerTier; + set => MagazineModule._regenerationPerTier = value; + } + + /// + /// Gets the current setting. + /// + public Scp127MagazineModule.RegenerationSettings ActiveSetting => MagazineModule.ActiveSettings; + + /// + /// Gets or sets a pause in bullets regeneration process. + /// + public float RemainingRegenPause + { + get => MagazineModule._remainingRegenPause; + set => MagazineModule._remainingRegenPause = value; + } + + /// + /// Gets or sets the amount of bullets that should be regenerated. + /// + public float RegenProgress + { + get => MagazineModule._regenProgress; + set => MagazineModule._regenProgress = value; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs index f9d8a74a0d..89bb189c42 100644 --- a/EXILED/Exiled.API/Features/Items/Item.cs +++ b/EXILED/Exiled.API/Features/Items/Item.cs @@ -22,6 +22,7 @@ namespace Exiled.API.Features.Items using InventorySystem.Items.Firearms.Ammo; using InventorySystem.Items.Jailbird; using InventorySystem.Items.Keycards; + using InventorySystem.Items.MarshmallowMan; using InventorySystem.Items.MicroHID; using InventorySystem.Items.Pickups; using InventorySystem.Items.Radio; @@ -218,7 +219,11 @@ public static Item Get(ItemBase itemBase) return itemBase switch { - InventorySystem.Items.Firearms.Firearm firearm => new Firearm(firearm), + InventorySystem.Items.Firearms.Firearm firearm => firearm.ItemTypeId switch + { + ItemType.GunSCP127 => new Scp127(firearm), + _ => new Firearm(firearm), + }, KeycardItem keycard => keycard switch { ChaosKeycardItem chaosKeycardItem => new ChaosKeycard(chaosKeycardItem), @@ -256,6 +261,7 @@ public static Item Get(ItemBase itemBase) _ => new Throwable(throwable), }, Scp1509Item scp1509 => new Scp1509(scp1509), + MarshmallowItem marshmallow => new Marshmallow(marshmallow), _ => new(itemBase), }; } @@ -318,7 +324,11 @@ public static T Get(ushort serial) /// The created. This can be cast as a subclass. public static Item Create(ItemType type, Player owner = null) => type.GetTemplate() switch { - InventorySystem.Items.Firearms.Firearm => new Firearm(type), + InventorySystem.Items.Firearms.Firearm => type switch + { + ItemType.GunSCP127 => new Scp127(), + _ => new Firearm(type), + }, KeycardItem keycard => keycard switch { ChaosKeycardItem => new ChaosKeycard(type), @@ -356,6 +366,7 @@ public static T Get(ushort serial) _ => new Throwable(type, owner), }, Scp1509Item => new Scp1509(), + MarshmallowItem => new Marshmallow(type, owner), _ => new(type), }; diff --git a/EXILED/Exiled.API/Features/Items/Jailbird.cs b/EXILED/Exiled.API/Features/Items/Jailbird.cs index b68a3473c2..4cc9a59c86 100644 --- a/EXILED/Exiled.API/Features/Items/Jailbird.cs +++ b/EXILED/Exiled.API/Features/Items/Jailbird.cs @@ -52,8 +52,8 @@ internal Jailbird() /// public float MeleeDamage { - get => Base._hitreg._damageMelee; - set => Base._hitreg._damageMelee = value; + get => Base.MeleeDamage; + set => Base.MeleeDamage = value; } /// @@ -61,8 +61,8 @@ public float MeleeDamage /// public float ChargeDamage { - get => Base._hitreg._damageCharge; - set => Base._hitreg._damageCharge = value; + get => Base._chargeDamage; + set => Base._chargeDamage = value; } /// @@ -70,8 +70,8 @@ public float ChargeDamage /// public float FlashDuration { - get => Base._hitreg._flashedDuration; - set => Base._hitreg._flashedDuration = value; + get => Base._flashedDuration; + set => Base._flashedDuration = value; } /// @@ -79,17 +79,17 @@ public float FlashDuration /// public float ConcussionDuration { - get => Base._hitreg._concussionDuration; - set => Base._hitreg._concussionDuration = value; + get => Base._concussionDuration; + set => Base._concussionDuration = value; } /// - /// Gets or sets the radius of the Jailbird's hit register. + /// Gets or sets the radius of the Jailbird's hit radius. /// public float Radius { - get => Base._hitreg._hitregRadius; - set => Base._hitreg._hitregRadius = value; + get => Base._hitregRadius; + set => Base._hitregRadius = value; } /// @@ -97,10 +97,10 @@ public float Radius /// public float TotalDamageDealt { - get => Base._hitreg.TotalMeleeDamageDealt; + get => Base.TotalMeleeDamageDealt; set { - Base._hitreg.TotalMeleeDamageDealt = value; + Base.TotalMeleeDamageDealt = value; Base._deterioration.RecheckUsage(); } } diff --git a/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs b/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs index 8d8bdad39d..bab50d19ce 100644 --- a/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs +++ b/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs @@ -43,7 +43,8 @@ internal ChaosKeycard(ItemType type) /// /// Gets the this encapsulates. /// - public SnakeEngine SnakeEngine => Base._localEngine; + /// Can be null, but shouldn't be during usage. + public SnakeEngine SnakeEngine => ChaosKeycardItem.SnakeSessions.TryGetValue(Serial, out SnakeEngine engine) ? engine : null; /// /// Returns the Keycard in a human readable format. diff --git a/EXILED/Exiled.API/Features/Items/Marshmallow.cs b/EXILED/Exiled.API/Features/Items/Marshmallow.cs new file mode 100644 index 0000000000..349fe342fb --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/Marshmallow.cs @@ -0,0 +1,102 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items +{ + using CustomPlayerEffects; + using Exiled.API.Interfaces; + using InventorySystem.Items.MarshmallowMan; + using PlayerStatsSystem; + using UnityEngine; + + /// + /// A wrapper class for . + /// + public class Marshmallow : Item, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// The base class. + public Marshmallow(MarshmallowItem itemBase) + : base(itemBase) + { + Base = itemBase; + } + + /// + /// Initializes a new instance of the class. + /// + /// The of the marshmallow item. + /// The owner of the marshmallow item. Leave for no owner. + internal Marshmallow(ItemType type, Player owner = null) + : base((MarshmallowItem)(owner ?? Server.Host).Inventory.CreateItemInstance(new(type, 0), false)) + { + } + + /// + /// Gets the that this class is encapsulating. + /// + public new MarshmallowItem Base { get; } + + /// + /// Gets a value indicating whether this marshmallow man is evil. + /// + /// See in regards to making a marshmallow evil. + public bool Evil => Base.EvilMode; + + /// + /// Gets or sets the of the marshmallow man that would be used if he was evil. + /// + public AhpStat.AhpProcess EvilAhpProcess + { + get => Base.EvilAHPProcess; + set + { + if (Evil && value is null) + return; + + Base.EvilAHPProcess = value; + } + } + + /// + /// Cackles for the owner even if they are not evil. + /// + /// How long until the player can cackle again (negative values do not affect current cooldown). + /// How long players near the marshmallow man get effected by . + public void Cackle(double cooldown = -1, float duration = 5) + { + if (cooldown >= 0) + Base._cackleCooldown.Trigger(cooldown); + + Base.ServerSendPublicRpc(writer => + { + writer.WriteByte(4); + Base._cackleCooldown.WriteCooldown(writer); + }); + + foreach (Player player in Player.List) + { + if (Vector3.Distance(player.Position, Owner.Position) <= 5F && player.CurrentItem is not Marshmallow { Evil: true }) + player.EnableEffect(duration); + } + } + + /// + /// Makes the owner of this marshmallow evil. You CANNOT undo this without resetting the player. + /// + /// The of the new evil player. + public void MakeEvil(AhpStat.AhpProcess evilProcess = null) + { + if (Evil) + return; + + Base.ReleaseEvil(evilProcess ?? EvilAhpProcess ?? Owner.GetModule().ServerAddProcess(450F, 450F, 0F, 1F, 0F, true)); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Items/Scp127.cs b/EXILED/Exiled.API/Features/Items/Scp127.cs new file mode 100644 index 0000000000..2c71fbe4bb --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/Scp127.cs @@ -0,0 +1,274 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items +{ + using System.Collections.Generic; + using System.Linq; + + using InventorySystem.Items.Firearms.Modules; + using InventorySystem.Items.Firearms.Modules.Scp127; + using UnityEngine; + + /// + /// Represents SCP-127. + /// + public class Scp127 : Firearm + { + #pragma warning disable SA1401 + /// + /// Custom amount of max HS. + /// + internal float? CustomHsMax; + #pragma warning restore SA1401 + + /// + /// Initializes a new instance of the class. + /// + /// + public Scp127(InventorySystem.Items.Firearms.Firearm itemBase) + : base(itemBase) + { + foreach (ModuleBase module in Base.Modules) + { + switch (module) + { + case Scp127HumeModule humeModule: + HumeModule = humeModule; + break; + case Scp127TierManagerModule tierManagerModule: + TierManagerModule = tierManagerModule; + break; + case Scp127VoiceLineManagerModule voiceLineManagerModule: + VoiceLineManagerModule = voiceLineManagerModule; + break; + } + } + } + + /// + /// Initializes a new instance of the class. + /// + internal Scp127() + : this((InventorySystem.Items.Firearms.Firearm)Server.Host.Inventory.CreateItemInstance(new(ItemType.GunSCP127, 0), false)) + { + } + + /// + /// Gets a collection of all active HS sessions. + /// + public static List ActiveHumeShieldSessions => Scp127HumeModule.ServerActiveSessions; + + /// + /// Gets the instance. + /// + public Scp127HumeModule HumeModule { get; } + + /// + /// Gets the instance. + /// + public Scp127TierManagerModule TierManagerModule { get; } + + /// + /// Gets the instance. + /// + public Scp127VoiceLineManagerModule VoiceLineManagerModule { get; } + + /// + /// Gets or sets the maximum amount of HS. + /// + /// If setter is used, after tier chance this value won't be edited automatically. + public float HsMax + { + get => CustomHsMax ?? HumeModule.HsMax; + set => CustomHsMax = value; + } + + /// + /// Gets or sets a shield regeneration rate. + /// + public float ShieldRegenRate + { + get => HumeModule.ShieldRegenRate; + set => HumeModule.ShieldRegenRate = value; + } + + /// + /// Gets or sets a shield decay time. + /// + public float ShieldDecayRate + { + get => HumeModule.ShieldDecayRate; + set => HumeModule.ShieldDecayRate = value; + } + + /// + /// Gets or sets a pause before HS starts regeneration after damage being taken. + /// + public float ShieldOnDamagePause + { + get => HumeModule.ShieldOnDamagePause; + set => HumeModule.ShieldOnDamagePause = value; + } + + /// + /// Gets or sets a delay before HS starts dropping after unequipment. + /// + public float UnequipDecayDelay + { + get => HumeModule.UnequipDecayDelay; + set => HumeModule.UnequipDecayDelay = value; + } + + /// + /// Gets or sets a HumeShield regeneration. + /// + public float HsRegeneration + { + get => HumeModule.HsRegeneration; + set => HumeModule.HsRegeneration = value; + } + + /// + /// Gets or sets an experience bonus for kill. + /// + public float KillBonus + { + get => TierManagerModule.KillBonus; + set => TierManagerModule.KillBonus = value; + } + + /// + /// Gets or sets an amount of passive experience increase. + /// + public float PassiveExpAmount + { + get => TierManagerModule.PassiveExpAmount; + set => TierManagerModule.PassiveExpAmount = value; + } + + /// + /// Gets or sets an interval of passive experience increase. + /// + public float PassiveExpInterval + { + get => TierManagerModule.PassiveExpInterval; + set => TierManagerModule.PassiveExpInterval = value; + } + + /// + /// Gets or sets a collection of all tier thresholds. + /// + public Scp127TierManagerModule.TierThreshold[] TierThresholds + { + get => TierManagerModule.Thresholds; + set => TierManagerModule.Thresholds = value; + } + + /// + /// Gets or sets current tier. + /// + public Scp127Tier CurrentTier + { + get => TierManagerModule.CurTier; + set => TierManagerModule.CurTier = value; + } + + /// + /// Gets or sets the current experience amount. + /// + public float Experience + { + get => TierManagerModule.ServerExp; + set => TierManagerModule.ServerExp = value; + } + + /// + /// Gets the instance record. + /// + public Scp127TierManagerModule.InstanceRecord InstanceRecord => Scp127TierManagerModule.GetRecord(Serial); + + /// + /// Gets the Owner stats. + /// + public Scp127TierManagerModule.OwnerStats OwnerStats => Scp127TierManagerModule.GetStats(Base); + + /// + /// Gets or sets all Voice Triggers. + /// + public Scp127VoiceTriggerBase[] VoiceTriggers + { + get => VoiceLineManagerModule._foundTriggers; + set => VoiceLineManagerModule._foundTriggers = value; + } + + /// + /// Gets a collection of players that are friends with this SCP-127. + /// + public IEnumerable Friends + { + get + { + if (!Scp127VoiceLineManagerModule.FriendshipMemory.TryGetValue(Serial, out HashSet uintSet)) + return null; + + return uintSet.Select(Player.Get); + } + } + + /// + /// Increases experience. + /// + /// Amount to add. + public void IncreaseExperience(float amount) => TierManagerModule.ServerIncreaseExp(Base, amount); + + /// + /// Sets owner stats. + /// + /// New experience amount. + public void SetOwnerStats(float exp) => TierManagerModule.ServerSetStats(exp); + + /// + /// Sends tier stats. + /// + /// New tier. + /// New progress. + public void SendTierStats(Scp127Tier tier, byte progress) => TierManagerModule.ServerSendStats(Serial, Owner.ReferenceHub, tier, progress); + + /// + /// Tries to play voice line. + /// + /// Voice line to play. + /// Priority of the play. + /// true if voice line has been played successfully. Otherwise, false. + public bool TryPlayVoiceLine(Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority priority = Scp127VoiceTriggerBase.VoiceLinePriority.Normal) + { + if (!VoiceLineManagerModule.TryFindVoiceLine(voiceLine, out Scp127VoiceTriggerBase triggerBase, out AudioClip audioClip)) + return false; + + VoiceLineManagerModule.ServerSendVoiceLine(triggerBase, null, audioClip, (byte)priority); + return true; + } + + /// + /// Checks if this instance of SCP-127 and have friendship. + /// + /// Target to check. + /// true if this instance of SCP-127 and have friendship. Otherwise, false. + public bool HasFriendship(Player player) => Scp127VoiceLineManagerModule.HasFriendship(Serial, player.ReferenceHub); + + /// + /// Adds player as a friend. + /// + /// Target to be added. + public void AddFriend(Player player) + { + HashSet uints = Scp127VoiceLineManagerModule.FriendshipMemory.GetOrAddNew(Serial); + uints.Add(player.NetId); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Lift.cs b/EXILED/Exiled.API/Features/Lift.cs index 469a33bd22..d191cd6764 100644 --- a/EXILED/Exiled.API/Features/Lift.cs +++ b/EXILED/Exiled.API/Features/Lift.cs @@ -47,6 +47,7 @@ public class Lift : IWrapper, IWorldSpace internal Lift(ElevatorChamber elevator) { Base = elevator; + ElevatorAutoReturn = elevator.GetComponent(); ElevatorChamberToLift.Add(elevator, this); internalDoorsList.AddRange(Elevator.AllElevatorDoors[Group]); @@ -73,6 +74,12 @@ internal Lift(ElevatorChamber elevator) /// public ElevatorChamber Base { get; } + /// + /// Gets the base . + /// + /// Would be null for any elevator that do not used . + public ElevatorAutoReturn ElevatorAutoReturn { get; } + /// /// Gets a value of the internal doors list. /// diff --git a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs index 0494d2e966..eaaf77cb7a 100644 --- a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs @@ -123,11 +123,11 @@ protected override void InitializeProperties(ItemBase itemBase) base.InitializeProperties(itemBase); if (itemBase is JailbirdItem jailbirdItem) { - MeleeDamage = jailbirdItem._hitreg._damageMelee; - ChargeDamage = jailbirdItem._hitreg._damageCharge; - FlashDuration = jailbirdItem._hitreg._flashedDuration; - ConcussionDuration = jailbirdItem._hitreg._concussionDuration; - Radius = jailbirdItem._hitreg._hitregRadius; + MeleeDamage = jailbirdItem.MeleeDamage; + ChargeDamage = jailbirdItem._chargeDamage; + FlashDuration = jailbirdItem._flashedDuration; + ConcussionDuration = jailbirdItem._concussionDuration; + Radius = Radius; } } } diff --git a/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs b/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs index b11c1cb0e9..935bc636ca 100644 --- a/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs @@ -15,7 +15,7 @@ namespace Exiled.API.Features.Pickups using BaseScp1509 = InventorySystem.Items.Scp1509.Scp1509Pickup; /// - /// A wrapper class for a Radio pickup. + /// A wrapper class for a Scp1509 pickup. /// public class Scp1509Pickup : Pickup, IWrapper { diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index a61d640a84..956fcf7f23 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -648,7 +648,7 @@ public ScpSpawnPreferences.SpawnPreferences ScpPreferences /// /// Gets a value indicating whether the player is reloading a weapon. /// - public bool IsReloading => CurrentItem is Firearm firearm && !firearm.IsReloading; + public bool IsReloading => CurrentItem is Firearm firearm && firearm.IsReloading; /// /// Gets a value indicating whether the player is aiming with a weapon. @@ -1982,10 +1982,24 @@ public void SetRank(string name, UserGroup group) ReferenceHub.serverRoles.SetGroup(group, false, false); } - if (ServerStatic.PermissionsHandler.Members.ContainsKey(UserId)) + ServerStatic.PermissionsHandler.Members[UserId] = name; + } + + /// + /// If the rank(group) exists in the remote admin config, it will assign it to the player. + /// + /// The rank name to be set. + /// if the rank(group) was found and successfully assigned, otherwise. + public bool TrySetRank(string name) + { + if (ServerStatic.PermissionsHandler.Groups.TryGetValue(name, out UserGroup userGroup)) + { + ReferenceHub.serverRoles.SetGroup(userGroup, false, false); ServerStatic.PermissionsHandler.Members[UserId] = name; - else - ServerStatic.PermissionsHandler.Members.Add(UserId, name); + return true; + } + + return false; } /// @@ -2029,6 +2043,21 @@ public void Broadcast(Broadcast broadcast, bool shouldClearPrevious = false) Broadcast(broadcast.Duration, broadcast.Content, broadcast.Type, shouldClearPrevious); } + /// + /// Send an to the player. + /// + /// The to be broadcasted. + /// if Cassie failed to play it or it's play nothing, otherwise it's return the duration of the annoucement. + public float CassieAnnouncement(global::Cassie.CassieAnnouncement cassieAnnouncement) + { + global::Cassie.CassieAnnouncementDispatcher.CurrentAnnouncement.OnStartedPlaying(); + global::Cassie.CassieTtsPayload payload = cassieAnnouncement.Payload; + if (!global::Cassie.CassieTtsAnnouncer.TryPlay(payload, out float totalduration)) + return 0; + payload.SendToHubsConditionally(x => x == ReferenceHub); + return totalduration; + } + /// /// Drops an item from the player's inventory. /// @@ -2061,10 +2090,12 @@ public void DropItem(Item item, bool isThrown = false) /// Dropped item's . public Pickup DropHeldItem() { - if (CurrentItem is null) + Item item = CurrentItem; + + if (item is null) return null; - return DropItem(CurrentItem); + return DropItem(item); } /// @@ -3449,10 +3480,7 @@ public void SyncEffect(Effect effect) { if (effect.IsEnabled) { - EnableEffect(effect.Type, effect.Duration, effect.AddDurationIfActive); - - if (effect.Intensity > 0) - ChangeEffectIntensity(effect.Type, effect.Intensity, effect.Duration); + EnableEffect(effect.Type, effect.Intensity, effect.Duration, effect.AddDurationIfActive); } } @@ -3580,8 +3608,7 @@ public void ChangeEffectIntensity(byte intensity, float duration = 0) { if (ReferenceHub.playerEffectsController.TryGetEffect(out T statusEffect)) { - statusEffect.Intensity = intensity; - statusEffect.ServerChangeDuration(duration, true); + statusEffect.ServerSetState(intensity, duration, false); } } @@ -3595,8 +3622,7 @@ public void ChangeEffectIntensity(EffectType type, byte intensity, float duratio { if (TryGetEffect(type, out StatusEffectBase statusEffect)) { - statusEffect.Intensity = intensity; - statusEffect.ServerChangeDuration(duration, false); + statusEffect.ServerSetState(intensity, duration, false); } } diff --git a/EXILED/Exiled.API/Features/Recontainer.cs b/EXILED/Exiled.API/Features/Recontainer.cs index 17f59c97d5..dbc31a35bf 100644 --- a/EXILED/Exiled.API/Features/Recontainer.cs +++ b/EXILED/Exiled.API/Features/Recontainer.cs @@ -7,6 +7,7 @@ namespace Exiled.API.Features { + using System; using System.Collections.Generic; using System.Linq; @@ -33,7 +34,8 @@ public static class Recontainer /// /// Gets a value indicating whether the C.A.S.S.I.E is currently busy. /// - public static bool IsCassieBusy => Base.CassieBusy; + [Obsolete("Use Cassie.IsSpeaking instead")] + public static bool IsCassieBusy => Cassie.IsSpeaking; /// /// Gets a value about how many generator have been activated. @@ -61,11 +63,8 @@ public static bool IsContainmentZoneLocked /// /// Gets or sets the delay to wait before overcharging. /// - public static float OverchargeDelay - { - get => Base._activationDelay; - set => Base._activationDelay = value; - } + [Obsolete("Will be removed in Exiled 10, patch the Cassie079RecontainAnnouncement ctor if you need this functionality")] + public static float OverchargeDelay { get; set; } /// /// Gets or sets the lockdown duration. @@ -188,7 +187,7 @@ public static bool IsContainmentSequenceSuccessful /// /// The announcement to play. /// The glitchy multiplier. - public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, glitchyMultiplier); + public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, false, false, null); /// /// Begins the overcharge procedure. @@ -199,7 +198,6 @@ public static void BeginOvercharge(bool endOvercharge = true) Base.BeginOvercharge(); if (endOvercharge) { - Base._delayStopwatch.Stop(); Base._unlockStopwatch.Start(); } } @@ -228,7 +226,7 @@ public static void BeginOvercharge(bool endOvercharge = true) /// /// Begins the recontainment procedure. /// - public static void Recontain() => Base.Recontain(); + public static void Recontain() => Base.Recontain(false); /// /// Refreshes the activator. diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs index 2b0d75cf00..9a1156833e 100644 --- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs +++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs @@ -300,6 +300,30 @@ public BasicRagdoll Ragdoll /// public SpectatableModuleBase SpectatableModuleBase => FirstPersonController.SpectatorModule; + /// + /// Tries to get the of a specified bone. + /// + /// The bone to get the of. + /// + /// When this method returns, contains the of the specified bone, if found; + /// otherwise, null. + /// + /// true if the bone transform was found; otherwise, false. + public bool TryGetBoneTransform(HumanBodyBones bone, out Transform boneTransform) + { + boneTransform = null; + + if (Model is not AnimatedCharacterModel animatedModel) + return false; + + Animator animator = animatedModel.Animator; + if (animator == null || animator.avatar == null || !animator.avatar.isValid || !animator.avatar.isHuman) + return false; + + boneTransform = animator.GetBoneTransform(bone); + return boneTransform != null; + } + /// /// Resets the 's stamina. /// diff --git a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs index 1c015e2ff0..6283226eb4 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs @@ -271,8 +271,7 @@ public void Attack(Player player) else { cardiacArrest.SetAttacker(AttackAbility.Owner); - cardiacArrest.Intensity = 1; - cardiacArrest.ServerChangeDuration(AttackAbility._statusEffectDuration, false); + cardiacArrest.ServerSetState(1, AttackAbility._statusEffectDuration, false); } SenseAbility.OnServerHit(AttackAbility._target); diff --git a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs index a59e699ac9..6e78b6c662 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs @@ -16,6 +16,8 @@ namespace Exiled.API.Features.Roles using PlayerRoles.PlayableScps.Scp096; using PlayerRoles.Subroutines; + using UnityEngine; + using Scp096GameRole = PlayerRoles.PlayableScps.Scp096.Scp096Role; /// @@ -139,6 +141,20 @@ internal Scp096Role(Scp096GameRole baseRole) /// public bool AttackPossible => AttackAbility.AttackPossible; + /// + /// Gets the head transform of SCP-096's character model. + /// + public Transform HeadTransform + { + get + { + if (Model is not Scp096CharacterModel scp96AnimatedCharacterModel) + return null; + + return scp96AnimatedCharacterModel.Head; + } + } + /// /// Gets or sets the Charge Ability Cooldown. /// @@ -306,4 +322,4 @@ public void Charge(float cooldown = 1f) /// The Spawn Chance. public float GetSpawnChance(List alreadySpawned) => Base.GetSpawnChance(alreadySpawned); } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs b/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs index a4c9ba78cf..170bda116a 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs @@ -20,7 +20,7 @@ namespace Exiled.API.Features.Roles /// /// Defines a role that represents SCP-1507. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class Scp1507Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp { /// diff --git a/EXILED/Exiled.API/Features/Room.cs b/EXILED/Exiled.API/Features/Room.cs index a81a24173f..846a76509c 100644 --- a/EXILED/Exiled.API/Features/Room.cs +++ b/EXILED/Exiled.API/Features/Room.cs @@ -506,6 +506,7 @@ private static RoomType FindType(GameObject gameObject) "HCZ_ChkpB" => RoomType.HczElevatorB, "HCZ_127" => RoomType.Hcz127, "HCZ_ServerRoom" => RoomType.HczServerRoom, + "HCZ_Intersection_Ramp" => RoomType.HczLoadingBay, "EZ_GateA" => RoomType.EzGateA, "EZ_GateB" => RoomType.EzGateB, "EZ_ThreeWay" => RoomType.EzTCross, diff --git a/EXILED/Exiled.API/Features/Scp559.cs b/EXILED/Exiled.API/Features/Scp559.cs index 08fc899047..d05702b351 100644 --- a/EXILED/Exiled.API/Features/Scp559.cs +++ b/EXILED/Exiled.API/Features/Scp559.cs @@ -18,7 +18,7 @@ namespace Exiled.API.Features /// /// Represents a cake. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class Scp559 : IWrapper, IPosition { /// @@ -50,20 +50,34 @@ public Scp559(Scp559Cake cakeBase) /// /// Gets a with spawnpoint in rooms. /// - public static Dictionary SpawnPositions => Scp559Cake.Spawnpoints; + public static Dictionary SpawnPositions { get; } = Scp559Spawnpoint.InstancesPerRoom.ToDictionary(kvp => kvp.Key.Name, kvp => + { + Transform roomTransform = kvp.Key.transform; + Transform spawnTransform = kvp.Value.transform; + + Vector3 localPos = roomTransform.InverseTransformPoint(spawnTransform.position); + + return new Vector4(localPos.x, localPos.y, localPos.z, spawnTransform.eulerAngles.y); + }); /// /// Gets the list of all available spawnpoints. /// - public static List AvailableSpawnpoints => Scp559Cake.PossiblePositions; + public static List AvailableSpawnpoints => Scp559Cake.PossibleSpawnpoints.Select(spawnpoint => + { + Transform t = spawnpoint.transform; + return new Vector4(t.position.x, t.position.y, t.position.z, t.eulerAngles.y); + }).ToList(); /// /// Gets or sets offset for spawning near pedestals. /// public static Vector3 PedestalOffset { - get => Scp559Cake.PedestalOffset; - set => Scp559Cake.PedestalOffset.Set(value.x, value.y, value.z); + get => new(0, -Scp559Spawnpoint.PedestalHeight, 0); + + [Obsolete("Setter no longer works")] + set { } } /// diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs index 96b8311fdf..825cfb3566 100644 --- a/EXILED/Exiled.API/Features/Server.cs +++ b/EXILED/Exiled.API/Features/Server.cs @@ -111,7 +111,27 @@ public static string Name /// /// Gets the actual ticks per second of the server. /// - public static double Tps => Math.Round(1f / Time.smoothDeltaTime); + public static double Tps + { + get + { + double delta = Time.deltaTime; + + if (delta <= 0) + return MaxTps; + + double tps = 1d / delta; + + tps = Math.Min(tps, MaxTps); + + return tps; + } + } + + /// + /// Gets the average ticks per second of the server. + /// + public static double SmoothTps => Math.Round(1f / Time.smoothDeltaTime); /// /// Gets or sets the max ticks per second of the server. diff --git a/EXILED/Exiled.API/Features/Waves/TimedWave.cs b/EXILED/Exiled.API/Features/Waves/TimedWave.cs index 8856727c58..6e9a5c55bf 100644 --- a/EXILED/Exiled.API/Features/Waves/TimedWave.cs +++ b/EXILED/Exiled.API/Features/Waves/TimedWave.cs @@ -193,13 +193,13 @@ public static List GetTimedWaves() /// Plays the announcement for this wave. /// /// Wave must implement . - public void PlayAnnouncement() => Announcement?.PlayAnnouncement(new()); + public void PlayAnnouncement() => Announcement?.PlayAnnouncement([], Base as IAnnouncedWave); /// /// Plays the announcement for this wave. /// /// Wave must implement . /// The list of Player to spawn. - public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList()); + public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList(), Base as IAnnouncedWave); } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Window.cs b/EXILED/Exiled.API/Features/Window.cs index e5a1624e0d..2d327ff0c4 100644 --- a/EXILED/Exiled.API/Features/Window.cs +++ b/EXILED/Exiled.API/Features/Window.cs @@ -231,6 +231,7 @@ public void DamageWindow(float amount, DamageHandlerBase handler) RoomType.HczEzCheckpointB => GlassType.HczEzCheckpointB, RoomType.EzGateA when Base.name[7] == '5' => GlassType.GateAArmory, RoomType.EzGateA => GlassType.GateAPit, + RoomType.HczLoadingBay => GlassType.HczLoadingBay, _ => GlassType.Unknown, }, "Window" => Room?.Type switch diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs index fa39569e0a..182f47155e 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs @@ -1013,15 +1013,6 @@ private void OnInternalOwnerHandcuffing(HandcuffingEventArgs ev) continue; OnOwnerHandcuffing(new OwnerHandcuffingEventArgs(item, ev)); - - if (!ev.IsAllowed) - continue; - - ev.Target.RemoveItem(item); - - TrackedSerials.Remove(item.Serial); - - Spawn(ev.Target, item, ev.Target); } } diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index f29e2d525c..afce01ccdf 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -790,6 +790,12 @@ public bool TryAddFriendlyFire(Dictionary ffRules, bool overw return true; } + /// + /// Returns the CustomRole in a human-readable format. + /// + /// A string containing CustomRole-related data. + public override string ToString() => $"{Name} ({Id})"; + /// /// Tries to register this role. /// diff --git a/EXILED/Exiled.CustomRoles/Commands/Get.cs b/EXILED/Exiled.CustomRoles/Commands/Get.cs new file mode 100644 index 0000000000..7d96d5f6b4 --- /dev/null +++ b/EXILED/Exiled.CustomRoles/Commands/Get.cs @@ -0,0 +1,123 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.CustomRoles.Commands +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using System.Text; + + using CommandSystem; + using Exiled.API.Extensions; + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.CustomRoles.API; + using Exiled.CustomRoles.API.Features; + using Exiled.Permissions.Extensions; + using HarmonyLib; + + /// + /// The command to get specified player(s) current custom roles. + /// + internal sealed class Get : ICommand + { + private Get() + { + } + + /// + /// Gets the command instance. + /// + public static Get Instance { get; } = new(); + + /// + public string Command => "get"; + + /// + public string[] Aliases { get; } = Array.Empty(); + + /// + public string Description => "Gets the specified player(s)' current custom role(s)."; + + /// + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + if (!sender.CheckPermission("customroles.get")) + { + response = "Permission Denied, required: customroles.get"; + return false; + } + + List players = ListPool.Pool.Get(); + + if (arguments.Count > 0) + { + string identifier = string.Join(" ", arguments); + + switch (identifier.ToLower()) + { + case "*": + case "all": + players.AddRange(Player.List); + break; + default: + players.AddRange(Player.GetProcessedData(arguments)); + break; + } + + if (players.IsEmpty()) + { + if (arguments.Count > 0 || !Player.TryGet(sender, out Player player)) + { + response = $"Player not found: {identifier}"; + return false; + } + + players.Add(player); + } + } + else + { + response = "get "; + return false; + } + + StringBuilder builder = StringBuilderPool.Pool.Get(); + + builder.AppendLine(); + builder.AppendLine("====================== Custom Roles ======================"); + + foreach (Player target in players) + { + ReadOnlyCollection roles = target.GetCustomRoles(); + builder.Append((target.DisplayNickname + (target.HasCustomName ? $" ({target.Nickname})" : string.Empty)).PadRight(30 + (target.HasCustomName ? 23 : 0))); + builder.Append(" "); + builder.Append($"({target.Id})".PadRight(5)); + if (roles.IsEmpty()) + { + builder.AppendLine(" | No Custom Role"); + } + else + { + // builder.Append($" | [{string.Join(", ", roles.Select(role => $"{role}"))}]"); + builder.Append(" | ["); + builder.Append(string.Join(", ", roles.Select(role => $"{role}"))); + builder.AppendLine("]"); + } + } + + builder.AppendLine("=========================================================="); + + ListPool.Pool.Return(players); + + response = StringBuilderPool.Pool.ToStringReturn(builder); + return true; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.CustomRoles/Commands/Give.cs b/EXILED/Exiled.CustomRoles/Commands/Give.cs index 2f74b46498..9666bff990 100644 --- a/EXILED/Exiled.CustomRoles/Commands/Give.cs +++ b/EXILED/Exiled.CustomRoles/Commands/Give.cs @@ -83,7 +83,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s string identifier = string.Join(" ", arguments.Skip(1)); - switch (identifier) + switch (identifier.ToLower()) { case "*": case "all": diff --git a/EXILED/Exiled.CustomRoles/Commands/Parent.cs b/EXILED/Exiled.CustomRoles/Commands/Parent.cs index f64facabec..fd42b5e497 100644 --- a/EXILED/Exiled.CustomRoles/Commands/Parent.cs +++ b/EXILED/Exiled.CustomRoles/Commands/Parent.cs @@ -41,12 +41,13 @@ public override void LoadGeneratedCommands() RegisterCommand(Give.Instance); RegisterCommand(Info.Instance); RegisterCommand(List.List.Instance); + RegisterCommand(Get.Instance); } /// protected override bool ExecuteParent(ArraySegment arguments, ICommandSender sender, out string response) { - response = "Invalid subcommand! Available: give, info, list"; + response = "Invalid subcommand! Available: give, info, list, get"; return false; } } diff --git a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj index 78b2030580..cd1a8b4769 100644 --- a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj +++ b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj @@ -49,4 +49,4 @@ if [[ ! -z "$EXILED_DEV_REFERENCES" ]]; then cp "$(OutputPath)$(AssemblyName).dll" "$EXILED_DEV_REFERENCES/Plugins/"; fi - + \ No newline at end of file diff --git a/EXILED/Exiled.Events/Commands/TpsCommand.cs b/EXILED/Exiled.Events/Commands/TpsCommand.cs index 722de3b61e..14c0def05e 100644 --- a/EXILED/Exiled.Events/Commands/TpsCommand.cs +++ b/EXILED/Exiled.Events/Commands/TpsCommand.cs @@ -15,7 +15,6 @@ namespace Exiled.Events.Commands /// /// Command for showing current server TPS. /// - [CommandHandler(typeof(RemoteAdminCommandHandler))] [CommandHandler(typeof(GameConsoleCommandHandler))] public class TpsCommand : ICommand { @@ -31,7 +30,7 @@ public class TpsCommand : ICommand /// public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) { - double diff = Server.Tps / Server.MaxTps; + double diff = Server.SmoothTps / Server.MaxTps; string color = diff switch { > 0.9 => "green", @@ -39,7 +38,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s _ => "red" }; - response = $"{Server.Tps}/{Server.MaxTps}"; + response = $"{Server.SmoothTps}/{Server.MaxTps}"; return true; } } diff --git a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs index a8b986c171..abd2f4877f 100644 --- a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs @@ -7,39 +7,70 @@ namespace Exiled.Events.EventArgs.Cassie { + using System; + using System.Text; + + using Exiled.API.Features.Pools; + using global::Cassie; using Interfaces; + using Subtitles; /// /// Contains all the information after sending a C.A.S.S.I.E. message. /// public class SendingCassieMessageEventArgs : IDeniableEvent { + private readonly CassieAnnouncement announcement; + private readonly CassieTtsPayload payload; + + private string customSubtitles; + private float glitchScale; + /// /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - /// - /// - /// + /// The announcement to populate all properties from. + /// + /// /// - /// - /// - /// - /// - /// - /// - /// Indicates whether the event can be executed. - public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise, bool customAnnouncement, string customSubtitles, bool isAllowed = true) + public SendingCassieMessageEventArgs(CassieAnnouncement annc, bool isAllowed = true) { - Words = words; - CustomSubtitles = customSubtitles; - MakeHold = makeHold; - MakeNoise = makeNoise; - IsCustomAnnouncement = customAnnouncement; + announcement = annc; + payload = annc.Payload; + + Words = payload.Content; + switch (payload.SubtitleSource) + { + case CassieTtsPayload.SubtitleMode.None: + case CassieTtsPayload.SubtitleMode.Automatic: + CustomSubtitles = string.Empty; + break; + case CassieTtsPayload.SubtitleMode.Custom: + CustomSubtitles = payload._customSubtitle; + break; + case CassieTtsPayload.SubtitleMode.FromTranslation: + StringBuilder builder = StringBuilderPool.Pool.Get(); + SubtitleController controller = SubtitleController.Singleton; + + foreach (SubtitlePart part in payload._subtitleMessage.SubtitleParts) + { + Subtitle subtitle = controller.Subtitles[part.Subtitle]; + builder.Append(controller.GetTranslation(subtitle)); + } + + CustomSubtitles = StringBuilderPool.Pool.ToStringReturn(builder); + + break; + default: + CustomSubtitles = string.Empty; + break; + } + + MakeHold = payload.PlayBackground; + GlitchScale = annc.GlitchScale; + MakeNoise = annc.GlitchScale is not 0; + SubtitleSource = payload.SubtitleSource; + IsAllowed = isAllowed; } @@ -51,13 +82,38 @@ public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise /// /// Gets or sets the message subtitles. /// - public string CustomSubtitles { get; set; } + public string CustomSubtitles + { + get => customSubtitles; + set + { + if (customSubtitles != value) + SubtitleSource = CassieTtsPayload.SubtitleMode.Custom; + + customSubtitles = value; + } + } /// /// Gets or sets a value indicating whether the message should be held. /// public bool MakeHold { get; set; } + /// + /// Gets or sets a value controlling how glitchy this CASSIE message is. + /// + public float GlitchScale + { + get => glitchScale; + set + { + if (!MakeNoise && value is not 0) + MakeNoise = true; + + glitchScale = value; + } + } + /// /// Gets or sets a value indicating whether the message should make noise. /// @@ -69,8 +125,50 @@ public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise public bool IsAllowed { get; set; } /// - /// Gets or sets a value indicating whether the message can be sent. + /// Gets or sets a value indicating whether the event can be executed. /// + [Obsolete("Useless and will be removed in Exiled 10.")] public bool IsCustomAnnouncement { get; set; } + + /// + /// Gets or sets a value indicating where the subtitles for this message came from. + /// + public CassieTtsPayload.SubtitleMode SubtitleSource { get; set; } + + /// + /// Gets a consisting of all properties in this event. + /// + public CassieAnnouncement Announcement + { + get + { + CassieTtsPayload newPayload; + + // I love readonly fields :) + if (SubtitleSource is CassieTtsPayload.SubtitleMode.FromTranslation) + { + newPayload = new CassieTtsPayload(Words, MakeHold, payload._subtitleMessage.SubtitleParts); + } + else + { + if (SubtitleSource is CassieTtsPayload.SubtitleMode.Automatic) + newPayload = new CassieTtsPayload(Words, true, MakeHold); + else + newPayload = new CassieTtsPayload(Words, CustomSubtitles, MakeHold); + } + + return announcement switch + { + CassieScpTerminationAnnouncement => + + // this is disabled via patch b/c termination messages are not modifiable at the stage the SendCassieMessage patch is in. + throw new InvalidOperationException("SendCassieMessage was called for a SCP termination message!"), + + CassieWaveAnnouncement waveAnnc => new CassieWaveAnnouncement(waveAnnc.Wave, newPayload), + Cassie079RecontainAnnouncement recontainAnnc => new Cassie079RecontainAnnouncement(recontainAnnc._callback, false, newPayload), + _ => new CassieAnnouncement(newPayload, 0, GlitchScale / (API.Features.Warhead.IsDetonated ? 2F : 1F) * (MakeNoise ? 1F : 0F)), + }; + } + } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs new file mode 100644 index 0000000000..fdd41cef5b --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs @@ -0,0 +1,22 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Interfaces +{ + using Exiled.API.Features.Items; + + /// + /// Represents all events related to the marshmallow man. + /// + public interface IMarshmallowEvent : IItemEvent + { + /// + /// Gets the marshmallow item related to this event. + /// + public Marshmallow Marshmallow { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs new file mode 100644 index 0000000000..616ad8f3e5 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs @@ -0,0 +1,20 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Interfaces +{ + /// + /// Represents all events related to SCP-127. + /// + public interface IScp127Event : IItemEvent + { + /// + /// Gets the SCP-127 instance, related to this event. + /// + public API.Features.Items.Scp127 Scp127 { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs index 1d6dcf3add..acb2463878 100644 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs @@ -14,7 +14,7 @@ namespace Exiled.Events.EventArgs.Interfaces /// /// Event args used for all related events. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public interface IScp1507Event : IPlayerEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs index d8a5537257..fc62383340 100644 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs @@ -12,7 +12,7 @@ namespace Exiled.Events.EventArgs.Interfaces /// /// Defines the base contract for all related events. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public interface IScp559Event : IExiledEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs new file mode 100644 index 0000000000..8e491ee0b1 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Item +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.MarshmallowMan; + + /// + /// Contains all information before a marshmallow man punches. + /// + public class CacklingEventArgs : IMarshmallowEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The marshmallow item of the player cackling. + /// Whether the player is allowed to cackle. + public CacklingEventArgs(MarshmallowItem marshmallow, bool isAllowed = true) + { + Marshmallow = Item.Get(marshmallow); + Player = Marshmallow.Owner; + IsAllowed = isAllowed; + } + + /// + /// Gets the player cackling. + /// + public Player Player { get; } + + /// + public API.Features.Items.Item Item => Marshmallow; + + /// + /// Gets the marshmallow item of the player cackling. + /// + public Marshmallow Marshmallow { get; } + + /// + /// Gets or sets a value indicating whether the player is allowed to cackle. + /// + public bool IsAllowed { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs new file mode 100644 index 0000000000..d2d927d95a --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Item +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.MarshmallowMan; + + /// + /// Contains all information before a marshmallow man punches. + /// + public class PunchingEventArgs : IMarshmallowEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The marshmallow item of the player attacking. + /// Whether the player is allowed to punch. + public PunchingEventArgs(MarshmallowItem marshmallow, bool isAllowed = true) + { + Marshmallow = Item.Get(marshmallow); + Player = Marshmallow.Owner; + IsAllowed = isAllowed; + } + + /// + /// Gets the player punching. + /// + public Player Player { get; } + + /// + public Item Item => Marshmallow; + + /// + /// Gets the marshmallow item of the player punching. + /// + public Marshmallow Marshmallow { get; } + + /// + /// Gets or sets a value indicating whether the punch is allowed. + /// + public bool IsAllowed { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs index 4c43eb1df8..d8d38cc474 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs @@ -7,15 +7,13 @@ namespace Exiled.Events.EventArgs.Map { + using System; + using API.Features; using API.Features.DamageHandlers; using API.Features.Roles; - using Interfaces; - using CustomAttackerHandler = API.Features.DamageHandlers.AttackerDamageHandler; - using DamageHandlerBase = PlayerStatsSystem.DamageHandlerBase; - /// /// Contains all information before C.A.S.S.I.E announces an SCP termination. /// @@ -27,16 +25,14 @@ public class AnnouncingScpTerminationEventArgs : IAttackerEvent, IDeniableEvent /// /// /// - /// - /// + /// + /// /// - public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHandlerBase) + public AnnouncingScpTerminationEventArgs(Player scp, string terminationCause) { Player = scp; Role = scp.Role; - DamageHandler = new CustomDamageHandler(scp, damageHandlerBase); - Attacker = DamageHandler.BaseIs(out CustomAttackerHandler customAttackerHandler) ? customAttackerHandler.Attacker : null; - TerminationCause = damageHandlerBase.CassieDeathAnnouncement.Announcement; + TerminationCause = terminationCause; IsAllowed = true; } @@ -58,11 +54,13 @@ public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHan /// /// Gets the player who killed the SCP. /// + [Obsolete("Attacker can no longer be acquired for this event. This will be readded in a different event.")] public Player Attacker { get; } /// /// Gets or sets the . /// + [Obsolete("DamageHandler can no longer be acquired for this event. This will be readded in a different event.")] public CustomDamageHandler DamageHandler { get; set; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs index 168a0f578e..038a3e16c4 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs @@ -18,8 +18,6 @@ namespace Exiled.Events.EventArgs.Player /// public class ReceivingEffectEventArgs : IPlayerEvent, IDeniableEvent { - private byte intensity; - /// /// Initializes a new instance of the class. /// @@ -32,9 +30,9 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int { Player = player; Effect = effect; - this.intensity = intensity; + Intensity = intensity; CurrentIntensity = currentIntensity; - Duration = duration; + Duration = intensity is 0 ? 0 : duration; } /// @@ -53,20 +51,9 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int public float Duration { get; set; } = 0; /// - /// Gets or sets the value of the new intensity of the effect. Setting this to 0 is the same as setting IsAllowed to - /// . + /// Gets or sets the value of the new intensity of the effect. /// - public byte Intensity - { - get => intensity; - set - { - intensity = value; - - if (intensity == 0) - IsAllowed = false; - } - } + public byte Intensity { get; set; } /// /// Gets the value of the intensity of this effect on the player. diff --git a/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs new file mode 100644 index 0000000000..6dce01109c --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs @@ -0,0 +1,41 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Player +{ + using API.Features; + using API.Features.Items; + using Interfaces; + using InventorySystem.Items.Usables.Scp1576; + + /// + /// Contains all information after a SCP-1576 transmission has ended. + /// + public class Scp1576TransmissionEndedEventArgs : IPlayerEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public Scp1576TransmissionEndedEventArgs(Player player, Scp1576Item scp1576Item) + { + Player = player; + Scp1576 = Item.Get(scp1576Item); + } + + /// + /// Gets the that the transmission ended for. + /// + public Player Player { get; } + + /// + /// Gets the instance. + /// + public Exiled.API.Features.Items.Scp1576 Scp1576 { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs index e25e9fd728..c6aeed7ffb 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs @@ -28,10 +28,14 @@ public class UsedItemEventArgs : IPlayerEvent, IUsableEvent /// /// /// - public UsedItemEventArgs(ReferenceHub player, UsableItem item) + /// + /// + /// + public UsedItemEventArgs(ReferenceHub player, UsableItem item, bool causedByHolstering) { Player = Player.Get(player); - Usable = Item.Get(item) is Usable usable ? usable : null; + Usable = Item.Get(item) as Usable; + CausedByHolstering = causedByHolstering; } /// @@ -46,5 +50,11 @@ public UsedItemEventArgs(ReferenceHub player, UsableItem item) /// Gets the player who used the item. /// public Player Player { get; } + + /// + /// Gets a value indicating whether this event was triggered by a player switching items (true) or by waiting after using the item (false). + /// + /// Use this value if you wish to keep the bug where you could switch items quickly to skip this event. + public bool CausedByHolstering { get; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs new file mode 100644 index 0000000000..533ccbb5ce --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp127 +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Contains all information before SCP-127 gains experience. + /// + public class GainedExperienceEventArgs : IScp127Event + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public GainedExperienceEventArgs(Scp127 scp127, float experience) + { + Scp127 = scp127; + Experience = experience; + Tier = Scp127.TierManagerModule.GetTierForExp(Experience + Scp127.Experience); + } + + /// + public Player Player => Scp127.Owner; + + /// + public Item Item => Scp127; + + /// + public Scp127 Scp127 { get; } + + /// + /// Gets the experience that SCP-127 has gained. + /// + public float Experience { get; } + + /// + /// Gets the tier. + /// + public Scp127Tier Tier { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs new file mode 100644 index 0000000000..6a1d7b738b --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs @@ -0,0 +1,59 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp127 +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Contains all information before SCP-127 gains experience. + /// + public class GainingExperienceEventArgs : IScp127Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + public GainingExperienceEventArgs(Scp127 scp127, float experience, bool isAllowed = true) + { + Scp127 = scp127; + Experience = experience; + IsAllowed = isAllowed; + } + + /// + public Player Player => Scp127.Owner; + + /// + public Item Item => Scp127; + + /// + public Scp127 Scp127 { get; } + + /// + public bool IsAllowed { get; set; } + + /// + /// Gets or sets the gaining experience. + /// + public float Experience { get; set; } + + /// + /// Gets or sets the new tier. + /// + public Scp127Tier Tier + { + get => Scp127.TierManagerModule.GetTierForExp(Experience + Scp127.Experience); + set => Experience = Scp127.TierManagerModule.GetExpForTier(value) - Scp127.Experience; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs new file mode 100644 index 0000000000..10810403d5 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs @@ -0,0 +1,52 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp127 +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Contains all information after SCP-127 voice line is played. + /// + public class TalkedEventArgs : IScp127Event + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + public TalkedEventArgs(Scp127 scp127, Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority voiceLinePriority) + { + Scp127 = scp127; + VoiceLine = voiceLine; + Priority = voiceLinePriority; + } + + /// + public Player Player => Scp127.Owner; + + /// + public Item Item => Scp127; + + /// + public Scp127 Scp127 { get; } + + /// + /// Gets a voice line which is played. + /// + public Scp127VoiceLinesTranslation VoiceLine { get; } + + /// + /// Gets a priority for this play. + /// + public Scp127VoiceTriggerBase.VoiceLinePriority Priority { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs new file mode 100644 index 0000000000..b8934566a8 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs @@ -0,0 +1,57 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp127 +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Contains all information before SCP-127 voice line is played. + /// + public class TalkingEventArgs : IScp127Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + public TalkingEventArgs(Scp127 scp127, Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority voiceLinePriority, bool isAllowed = true) + { + Scp127 = scp127; + VoiceLine = voiceLine; + Priority = voiceLinePriority; + IsAllowed = isAllowed; + } + + /// + public Player Player => Scp127.Owner; + + /// + public Item Item => Scp127; + + /// + public Scp127 Scp127 { get; } + + /// + public bool IsAllowed { get; set; } + + /// + /// Gets or sets a voice line which is played. + /// + public Scp127VoiceLinesTranslation VoiceLine { get; set; } + + /// + /// Gets or sets a priority for this play. + /// + public Scp127VoiceTriggerBase.VoiceLinePriority Priority { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs index c58330e252..c6ea947e55 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs @@ -18,7 +18,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 attacks door. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class AttackingDoorEventArgs : IScp1507Event, IDeniableEvent, IDoorEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs index ae5ebb8450..7ab56f98e2 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs @@ -16,7 +16,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 screams. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class ScreamingEventArgs : IScp1507Event, IDeniableEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs index 376eba5abf..5cc50f9352 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs @@ -19,7 +19,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before flamingos get spawned. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class SpawningFlamingosEventArgs : IDeniableEvent, IPlayerEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs index 0121d02d95..10b713052e 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 screams. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class UsingTapeEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs new file mode 100644 index 0000000000..d4935e6c92 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs @@ -0,0 +1,40 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp2536 +{ + using Christmas.Scp2536; + using Exiled.API.Features; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information after SCP-2536 chooses target for spawning. + /// + public class FoundPositionEventArgs : IPlayerEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public FoundPositionEventArgs(Player player, Scp2536Spawnpoint spawnpoint) + { + Player = player; + Spawnpoint = spawnpoint; + } + + /// + /// Gets the player near whom SCP-2536 will spawn. + /// + public Player Player { get; } + + /// + /// Gets or sets the spawn point where SCP will spawn. + /// + public Scp2536Spawnpoint Spawnpoint { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs index b8b99f9ac9..1a4a7408dc 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs @@ -15,7 +15,7 @@ namespace Exiled.Events.EventArgs.Scp559 /// /// Contains all information before a player interacts with SCP-559. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class InteractingScp559EventArgs : IScp559Event, IDeniableEvent, IPlayerEvent { /// @@ -23,12 +23,11 @@ public class InteractingScp559EventArgs : IScp559Event, IDeniableEvent, IPlayerE /// /// /// - /// - public InteractingScp559EventArgs(Scp559 scp559, Player player, bool isAllowed = true) + public InteractingScp559EventArgs(Scp559 scp559, Player player) { Player = player; Scp559 = scp559; - IsAllowed = isAllowed; + IsAllowed = scp559.RemainingSlices > 0 && PlayerRoles.PlayerRolesUtils.IsHuman(player.Role.Type); } /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs index 6e3a81f06a..c83baddd2c 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs @@ -16,7 +16,7 @@ namespace Exiled.Events.EventArgs.Scp559 /// /// Contains all information before SCP-559 spawns. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class SpawningEventArgs : IDeniableEvent, IScp559Event { /// diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index a1bdd040a2..adae6e21a8 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -21,6 +21,7 @@ namespace Exiled.Events using PlayerRoles.FirstPersonControl.NetworkMessages; using PlayerRoles.Ragdolls; using PlayerRoles.RoleAssign; + using Respawning; using UnityEngine.SceneManagement; using UserSettings.ServerSpecific; @@ -73,6 +74,7 @@ public override void OnEnabled() Handlers.Scp049.ActivatingSense += Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified += Handlers.Internal.Round.OnVerified; Handlers.Map.ChangedIntoGrenade += Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; + Handlers.Warhead.Detonated += Handlers.Internal.Round.OnWarheadDetonated; RoleAssigner.OnPlayersSpawned += Handlers.Server.OnAllPlayersSpawned; CharacterClassManager.OnRoundStarted += Handlers.Server.OnRoundStarted; @@ -95,6 +97,11 @@ public override void OnEnabled() FpcServerPositionDistributor.RoleSyncEvent += Handlers.Internal.Round.OnRoleSyncEvent; + LabApi.Events.Handlers.Scp127Events.Talking += Handlers.Scp127.OnTalking; + LabApi.Events.Handlers.Scp127Events.Talked += Handlers.Scp127.OnTalked; + LabApi.Events.Handlers.Scp127Events.GainingExperience += Handlers.Scp127.OnGainingExperience; + LabApi.Events.Handlers.Scp127Events.GainExperience += Handlers.Scp127.OnGainedExperience; + ServerConsole.ReloadServerName(); } @@ -135,6 +142,11 @@ public override void OnDisabled() LabApi.Events.Handlers.PlayerEvents.UnloadingWeapon -= Handlers.Player.OnUnloadingWeapon; FpcServerPositionDistributor.RoleSyncEvent -= Handlers.Internal.Round.OnRoleSyncEvent; + + LabApi.Events.Handlers.Scp127Events.Talking -= Handlers.Scp127.OnTalking; + LabApi.Events.Handlers.Scp127Events.Talked -= Handlers.Scp127.OnTalked; + LabApi.Events.Handlers.Scp127Events.GainingExperience -= Handlers.Scp127.OnGainingExperience; + LabApi.Events.Handlers.Scp127Events.GainExperience -= Handlers.Scp127.OnGainedExperience; } /// diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 4cedb7a21e..ff2833b79b 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -29,6 +29,7 @@ namespace Exiled.Events.Handlers.Internal using InventorySystem.Items.Firearms.Attachments.Components; using InventorySystem.Items.Usables; using InventorySystem.Items.Usables.Scp244.Hypothermia; + using InventorySystem.Items.Usables.Scp330; using Mirror; using PlayerRoles; using PlayerRoles.FirstPersonControl; @@ -43,7 +44,7 @@ namespace Exiled.Events.Handlers.Internal internal static class Round { /// - public static void OnServerOnUsingCompleted(ReferenceHub hub, UsableItem usable) => Handlers.Player.OnUsedItem(new (hub, usable)); + public static void OnServerOnUsingCompleted(ReferenceHub hub, UsableItem usable) => Handlers.Player.OnUsedItem(new (hub, usable, false)); /// public static void OnWaitingForPlayers() @@ -108,6 +109,9 @@ public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { if (ev.Role.IsDead() || !ev.Role.IsFpcRole()) ev.IsAllowed = false; + + if (ev.DamageHandlerBase is Exiled.Events.Patches.Fixes.FixMarshmallowManFF fixMarshamllowManFf) + ev.DamageHandlerBase = fixMarshamllowManFf.MarshmallowItem.NewDamageHandler; } /// @@ -136,7 +140,7 @@ public static void OnVerified(VerifiedEventArgs ev) } // Fix bug that player that Join do not receive information about other players Scale - foreach (Player player in Player.Enumerable) + foreach (Player player in ReferenceHub.AllHubs.Select(Player.Get)) { player.SetFakeScale(player.Scale, new List() { ev.Player }); @@ -178,6 +182,13 @@ public static RoleTypeId OnRoleSyncEvent(ReferenceHub viewerHub, ReferenceHub ow return actualRole; } + /// + public static void OnWarheadDetonated() + { + // fix for black candy + CandyBlack.Outcomes.RemoveAll(outcome => outcome is TeleportOutcome); + } + private static void GenerateAttachments() { foreach (FirearmType firearmType in EnumUtils.Values) diff --git a/EXILED/Exiled.Events/Handlers/Item.cs b/EXILED/Exiled.Events/Handlers/Item.cs index 9ac83aafd3..b1ca257f09 100644 --- a/EXILED/Exiled.Events/Handlers/Item.cs +++ b/EXILED/Exiled.Events/Handlers/Item.cs @@ -89,6 +89,16 @@ public static class Item /// public static Event JailbirdChangedWearState { get; set; } = new(); + /// + /// Invoked before a marshmallow man punches. + /// + public static Event Punching { get; set; } = new(); + + /// + /// Invoked before a marshmallow man cackles. + /// + public static Event Cackling { get; set; } = new(); + /// /// Called before the Jailbird's is changed. /// @@ -173,5 +183,17 @@ public static class Item /// /// The instance. public static void OnInspectedItem(InspectedItemEventArgs ev) => InspectedItem.InvokeSafely(ev); + + /// + /// Called before a marshmallow man punches. + /// + /// The instance. + public static void OnPunching(PunchingEventArgs ev) => Punching.InvokeSafely(ev); + + /// + /// Called before a marshmallow man cackles. + /// + /// The instance. + public static void OnCackling(CacklingEventArgs ev) => Cackling.InvokeSafely(ev); } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index 97e6137003..998b54f813 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -621,6 +621,11 @@ public class Player /// public static Event InteractingEmergencyButton { get; set; } = new(); + /// + /// Invoked after transmission has ended. + /// + public static Event Scp1576TransmissionEnded { get; set; } = new(); + /// /// Called before a player's emotion changed. /// @@ -1356,5 +1361,11 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item /// /// The instance. public static void OnInteractingEmergencyButton(InteractingEmergencyButtonEventArgs ev) => InteractingEmergencyButton.InvokeSafely(ev); + + /// + /// Called after a 1576 transmisiion has ended. + /// + /// The instance. + public static void OnScp1576TransmissionEnded(Scp1576TransmissionEndedEventArgs ev) => Scp1576TransmissionEnded.InvokeSafely(ev); } } diff --git a/EXILED/Exiled.Events/Handlers/Scp127.cs b/EXILED/Exiled.Events/Handlers/Scp127.cs new file mode 100644 index 0000000000..b3f86534d3 --- /dev/null +++ b/EXILED/Exiled.Events/Handlers/Scp127.cs @@ -0,0 +1,81 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Handlers +{ + using Exiled.Events.EventArgs.Scp127; + using Exiled.Events.Features; + using LabApi.Events.Arguments.Scp127Events; + +#pragma warning disable SA1623 + /// + /// SCP-127 event handlers. + /// + public static class Scp127 + { + /// + /// Invoked before SCP-127 voice line is played. + /// + public static Event Talking { get; set; } = new(); + + /// + /// Invoked after SCP-127 voice line is played. + /// + public static Event Talked { get; set; } = new(); + + /// + /// Invoked before SCP-127 gains experience. + /// + public static Event GainingExperience { get; set; } = new(); + + /// + /// Invoked after SCP-127 gains experience. + /// + public static Event GainedExperience { get; set; } = new(); + + /// + /// Called before SCP-127 voice line is played. + /// + /// The instance. + public static void OnTalking(Scp127TalkingEventArgs ev) + { + TalkingEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.VoiceLine, ev.Priority, ev.IsAllowed); + Talking.InvokeSafely(eventArgs); + + ev.Priority = eventArgs.Priority; + ev.VoiceLine = eventArgs.VoiceLine; + ev.IsAllowed = eventArgs.IsAllowed; + } + + /// + /// Called after SCP-127 voice line is played. + /// + /// The instance. + public static void OnTalked(Scp127TalkedEventArgs ev) + => Talked.InvokeSafely(new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.VoiceLine, ev.Priority)); + + /// + /// Called before SCP-127 gains experience. + /// + /// The instance. + public static void OnGainingExperience(Scp127GainingExperienceEventArgs ev) + { + GainingExperienceEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.ExperienceGain, ev.IsAllowed); + GainingExperience.InvokeSafely(eventArgs); + + ev.ExperienceGain = eventArgs.Experience; + ev.IsAllowed = eventArgs.IsAllowed; + } + + /// + /// Called after SCP-127 gains experience. + /// + /// The instance. + public static void OnGainedExperience(Scp127GainExperienceEventArgs ev) => + GainedExperience.InvokeSafely(new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.ExperienceGain)); + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Scp1507.cs b/EXILED/Exiled.Events/Handlers/Scp1507.cs index 63e4536d2c..f36b16d633 100644 --- a/EXILED/Exiled.Events/Handlers/Scp1507.cs +++ b/EXILED/Exiled.Events/Handlers/Scp1507.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.Handlers /// /// SCP-1507 related events. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public static class Scp1507 { /// diff --git a/EXILED/Exiled.Events/Handlers/Scp2536.cs b/EXILED/Exiled.Events/Handlers/Scp2536.cs index 3f7dfd1c58..8c0d272583 100644 --- a/EXILED/Exiled.Events/Handlers/Scp2536.cs +++ b/EXILED/Exiled.Events/Handlers/Scp2536.cs @@ -21,6 +21,11 @@ public static class Scp2536 /// public static Event FindingPosition { get; set; } = new(); + /// + /// Invoked once SCP-2536 has found a spawn location. + /// + public static Event FoundPosition { get; set; } = new(); + /// /// Invoked before SCP-2536 gives a gift to a player. /// @@ -37,6 +42,12 @@ public static class Scp2536 /// The instance. public static void OnFindingPosition(FindingPositionEventArgs ev) => FindingPosition.InvokeSafely(ev); + /// + /// Called after SCP-2536 chooses a target. + /// + /// The instance. + public static void OnFoundPosition(FoundPositionEventArgs ev) => FoundPosition.InvokeSafely(ev); + /// /// Called before SCP-2536 gives a gift to a player. /// diff --git a/EXILED/Exiled.Events/Handlers/Scp559.cs b/EXILED/Exiled.Events/Handlers/Scp559.cs index b17f520c9d..70d5387520 100644 --- a/EXILED/Exiled.Events/Handlers/Scp559.cs +++ b/EXILED/Exiled.Events/Handlers/Scp559.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.Handlers /// /// All SCP-559 related events. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public static class Scp559 { /// diff --git a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs index 0cb378ac02..1e7b55e3a8 100644 --- a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs +++ b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs @@ -8,87 +8,61 @@ namespace Exiled.Events.Patches.Events.Cassie { using System.Collections.Generic; + using System.Linq; using System.Reflection.Emit; using API.Features.Pools; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Cassie; - + using global::Cassie; using Handlers; - using HarmonyLib; using Respawning; using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Cassie), nameof(Cassie.SendingCassieMessage))] - [HarmonyPatch(typeof(RespawnEffectsController), nameof(RespawnEffectsController.PlayCassieAnnouncement))] + [HarmonyPatch(typeof(CassieAnnouncementDispatcher), nameof(CassieAnnouncementDispatcher.PlayNewAnnouncement))] internal static class SendingCassieMessage { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); + Label skipLabel = generator.DefineLabel(); Label returnLabel = generator.DefineLabel(); + newInstructions[0].WithLabels(skipLabel); + newInstructions.InsertRange( 0, new CodeInstruction[] { - // words new(OpCodes.Ldarg_0), + new(OpCodes.Isinst, typeof(CassieScpTerminationAnnouncement)), + new(OpCodes.Brtrue_S, skipLabel), - // makeHold - new(OpCodes.Ldarg_1), - - // makeNoise - new(OpCodes.Ldarg_2), - - // customAnnouncement - new(OpCodes.Ldarg_3), - - // customSubtitles - new(OpCodes.Ldarg_S, 4), + new(OpCodes.Ldarg_0), // isAllowed new(OpCodes.Ldc_I4_1), - // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(string, bool, bool, bool, string, bool); - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs))[0]), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Dup), + // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(CassieAnnouncement, bool); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs)).Single(ctor => ctor.GetParameters().Length == 2)), new(OpCodes.Dup), new(OpCodes.Dup), // Cassie.OnSendingCassieMessage(ev); new(OpCodes.Call, Method(typeof(Cassie), nameof(Cassie.OnSendingCassieMessage))), - // words = ev.Words - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Words))), + // annc = ev.Announcement + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Announcement))), new(OpCodes.Starg_S, 0), - // makeHold = ev.MakeHold - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeHold))), - new(OpCodes.Starg_S, 1), - - // makeNoise = ev.MakeNoise - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeNoise))), - new(OpCodes.Starg_S, 2), - - // customAnnouncement = ev.IsCustomAnnouncement - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsCustomAnnouncement))), - new(OpCodes.Starg_S, 3), - - // customSubtitles = ev.CustomSubtitles - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.CustomSubtitles))), - new(OpCodes.Starg_S, 4), - // if (!IsAllowed) // return; new(OpCodes.Callvirt, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsAllowed))), diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs b/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs new file mode 100644 index 0000000000..fec7811ecf --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs @@ -0,0 +1,65 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Item +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Item; + using HarmonyLib; + using InventorySystem.Items.MarshmallowMan; + + using static HarmonyLib.AccessTools; + + /// + /// Patch the . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Cackling))] + [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCackle))] + public class Cackling + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label retLabel = generator.DefineLabel(); + + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; + + newInstructions.InsertRange(index, new[] + { + // this; + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + + // true + new(OpCodes.Ldc_I4_1), + + // ev = new CacklingEventArgs(MarshmallowItem, bool); + new(OpCodes.Newobj, Constructor(typeof(CacklingEventArgs), new[] { typeof(MarshmallowItem), typeof(bool) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnCackling))), + + // if (!ev.IsAllowed) return + new(OpCodes.Callvirt, PropertyGetter(typeof(CacklingEventArgs), nameof(CacklingEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, retLabel), + }); + + newInstructions[newInstructions.Count - 1].WithLabels(retLabel); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs b/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs new file mode 100644 index 0000000000..15c74b57b1 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs @@ -0,0 +1,65 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Item +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Item; + using HarmonyLib; + using InventorySystem.Items.MarshmallowMan; + + using static HarmonyLib.AccessTools; + + /// + /// Patch the . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Punching))] + [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCmd))] + public class Punching + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label retLabel = generator.DefineLabel(); + + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; + + newInstructions[^1].WithLabels(retLabel); + + newInstructions.InsertRange(index, new[] + { + // this; + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + + // true + new(OpCodes.Ldc_I4_1), + + // ev = new PunchingEventArgs(MarshmallowItem, bool); + new(OpCodes.Newobj, Constructor(typeof(PunchingEventArgs), new[] { typeof(MarshmallowItem), typeof(bool) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnPunching))), + + // if (!ev.IsAllowed) return + new(OpCodes.Callvirt, PropertyGetter(typeof(PunchingEventArgs), nameof(PunchingEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, retLabel), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs index 0d53ebeefb..3033a0327d 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs @@ -7,6 +7,7 @@ namespace Exiled.Events.Patches.Events.Map { + using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; @@ -17,11 +18,12 @@ namespace Exiled.Events.Patches.Events.Map using Exiled.Events.EventArgs.Map; using HarmonyLib; using Respawning.Announcements; + using Subtitles; using static HarmonyLib.AccessTools; /// - /// Patches and + /// Patches and /// to add event. /// [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] @@ -30,8 +32,8 @@ internal static class AnnouncingChaosEntrance { private static IEnumerable TargetMethods() { - yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncementString)); - yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncementString)); + yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncement)); + yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncement)); } private static IEnumerable Transpiler(IEnumerable instruction, ILGenerator generator) @@ -70,6 +72,9 @@ private static IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncementString))] + [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncement))] internal static class AnnouncingNtfEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -39,8 +40,8 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Stloc_3) + offset; + int offset = 2; + int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(UnitNamingRule), nameof(UnitNamingRule.TranslateToCassie)))) + offset; newInstructions.InsertRange( index, @@ -50,10 +51,10 @@ private static IEnumerable Transpiler(IEnumerable]*?>"), new(OpCodes.Ldsfld, Field(typeof(string), nameof(string.Empty))), new(OpCodes.Call, Method(typeof(Regex), nameof(Regex.Replace), new System.Type[] { typeof(string), typeof(string), typeof(string) })), @@ -63,9 +64,9 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncementString))] + [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncement))] internal static class AnnouncingNtfMiniEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -35,15 +35,17 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Stloc_1) + 1; + newInstructions.InsertRange( - 0, + index, new CodeInstruction[] { // WaveAnnouncementBase new(OpCodes.Ldarg_0), // scpsLeft - new(OpCodes.Ldloc_0), + new(OpCodes.Ldloc_1), // null new(OpCodes.Ldnull), @@ -66,7 +68,7 @@ private static IEnumerable Transpiler(IEnumerable /// Patches - /// . + /// . /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingScpTermination))] - [HarmonyPatch(typeof(NineTailedFoxAnnouncer), nameof(NineTailedFoxAnnouncer.AnnounceScpTermination))] + [HarmonyPatch(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.OnStartedPlaying))] internal static class AnnouncingScpTermination { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); - LocalBuilder ev = generator.DeclareLocal(typeof(AnnouncingScpTerminationEventArgs)); + LocalBuilder cause = generator.DeclareLocal(typeof(string)); + LocalBuilder enumerator = generator.DeclareLocal(typeof(IEnumerator)); + + ExceptionBlock beginTry = new(ExceptionBlockType.BeginExceptionBlock); + ExceptionBlock beginFinally = new(ExceptionBlockType.BeginFinallyBlock); + ExceptionBlock endFinally = new(ExceptionBlockType.EndExceptionBlock); Label ret = generator.DefineLabel(); + Label entryLabel = generator.DefineLabel(); + Label loopLabel = generator.DefineLabel(); + Label leaveLabel = generator.DefineLabel(); + Label endFinallyLabel = generator.DefineLabel(); + + int offset = -1; + int index = newInstructions.FindIndex(i => i.LoadsField(Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts)))) + offset; + + newInstructions.RemoveRange(index, 2); + newInstructions.Insert(index, new CodeInstruction(OpCodes.Ldloc_S, cause)); - int offset = -4; - int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Newobj && (ConstructorInfo)i.operand == GetDeclaredConstructors(typeof(LabApi.Events.Arguments.ServerEvents.CassieQueuingScpTerminationEventArgs))[0]) + offset; + newInstructions[0].WithLabels(leaveLabel); newInstructions.InsertRange( - index, + 0, new[] - { - // Player.Get(scp) - new CodeInstruction(OpCodes.Ldarg_0), - new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), - - // hit - new(OpCodes.Ldarg_1), - - // AnnouncingScpTerminationEventArgs ev = new(Player, DamageHandlerBase) - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(AnnouncingScpTerminationEventArgs))[0]), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Stloc_S, ev.LocalIndex), - - // Map.OnAnnouncingScpTermination(ev) - new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), - - // if (!ev.IsAllowed) - // return; - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.IsAllowed))), - new(OpCodes.Brfalse_S, ret), - - // hit = ev.DamageHandler.Base - new(OpCodes.Ldloc_S, ev.LocalIndex), - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.DamageHandler))), - new(OpCodes.Callvirt, PropertyGetter(typeof(CustomDamageHandler), nameof(CustomDamageHandler.Base))), - new(OpCodes.Starg, 1), - - // announcement = ev.TerminationCause - new(OpCodes.Ldloc_S, ev.LocalIndex), - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), - new(OpCodes.Stloc_0), - }); + { + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts))), + new(OpCodes.Stloc_S, cause), + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.Victims))), + new(OpCodes.Callvirt, Method(typeof(IEnumerable), nameof(IEnumerable.GetEnumerator))), + new(OpCodes.Stloc_S, enumerator), + + // start of try + new CodeInstruction(OpCodes.Br_S, entryLabel).WithBlocks(beginTry), + + // start of loop + new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(loopLabel), + new(OpCodes.Callvirt, PropertyGetter(typeof(IEnumerator), nameof(IEnumerator.Current))), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(Footprint) })), + new(OpCodes.Ldloc_S, cause), + new(OpCodes.Newobj, Constructor(typeof(AnnouncingScpTerminationEventArgs), new[] { typeof(Player), typeof(string) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), + new(OpCodes.Stloc_S, cause), + + // entry point + new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(entryLabel), + new(OpCodes.Callvirt, Method(typeof(IEnumerator), nameof(IEnumerator.MoveNext))), + new(OpCodes.Brtrue_S, loopLabel), + + // end of loop + new(OpCodes.Leave, leaveLabel), + + // begin finally + new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithBlocks(beginFinally), + new(OpCodes.Brfalse, endFinallyLabel), + new(OpCodes.Ldloc_S, enumerator), + new(OpCodes.Callvirt, Method(typeof(IDisposable), nameof(IDisposable.Dispose))), + + // end of finally + new CodeInstruction(OpCodes.Endfinally).WithLabels(endFinallyLabel).WithBlocks(endFinally), + }); newInstructions[newInstructions.Count - 1].labels.Add(ret); diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs deleted file mode 100644 index 7193f8d17f..0000000000 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs +++ /dev/null @@ -1,68 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Patches.Events.Map -{ - using System.Collections.Generic; - using System.Reflection; - using System.Reflection.Emit; - using System.Text; - - using Exiled.API.Features.Pools; - using Exiled.Events.Attributes; - using Exiled.Events.EventArgs.Map; - using HarmonyLib; - using Respawning.Announcements; - - using static HarmonyLib.AccessTools; - - /// - /// Patches to prevent cassie from playing empty string. - /// - [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingNtfEntrance))] - [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] - [HarmonyPatch(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.PlayAnnouncement))] - internal static class AnnouncingTeamEntrance - { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - List newInstructions = ListPool.Pool.Get(instructions); - - Label returnLabel = generator.DefineLabel(); - - // the instruction that sends subtitles is called before stringReturn is created (and thus checked) so we need to move it so that empty (or disallowed) message's subtitles are not sent. - // this removes the Ldarg_0 and the CallVirt - int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.SendSubtitles)))); - CodeInstruction sendSubtitlesInstruction = newInstructions[index]; - newInstructions.RemoveRange(index - 2, 3); - - index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldsfld); - - newInstructions.InsertRange(index, new[] - { - // if (stringReturn == "") - // return; - new(OpCodes.Ldloc_S, 4), - new(OpCodes.Ldstr, string.Empty), - new(OpCodes.Ceq), - new(OpCodes.Brtrue_S, returnLabel), - - // send subtitles before cassie message, but after our check. - new(OpCodes.Ldarg_0), - new(OpCodes.Ldarg_1), - sendSubtitlesInstruction, - }); - - newInstructions[newInstructions.Count - 1].labels.Add(returnLabel); - - for (int z = 0; z < newInstructions.Count; z++) - yield return newInstructions[z]; - - ListPool.Pool.Return(newInstructions); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs index b379bdec1a..4af8bd4e11 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs @@ -89,14 +89,13 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(RoomConnectorSpawnpointBase), nameof(RoomConnectorSpawnpointBase.SetupAllRoomConnectors)))); - List GateAArmory, - - /// - /// Represents the door in . - /// - HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/EffectType.cs b/EXILED/Exiled.API/Enums/EffectType.cs index 9bed0519c9..e70e273e77 100644 --- a/EXILED/Exiled.API/Enums/EffectType.cs +++ b/EXILED/Exiled.API/Enums/EffectType.cs @@ -216,7 +216,7 @@ public enum EffectType /// /// Makes you a marshmallow guy. /// - // [Obsolete("Not functional in-game")] + [Obsolete("Not functional in-game")] Marshmallow, /// @@ -261,27 +261,27 @@ public enum EffectType Blurred, /// - /// Makes you a flamingo . + /// Makes you a flamingo. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] BecomingFlamingo, /// - /// Makes you a Child after eating Cake . + /// Makes you a Child after eating Cake. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] Scp559, /// - /// Scp956 found you . + /// Scp956 found you. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] Scp956Target, /// - /// you are snowed . + /// you are snowed. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] Snowed, /// @@ -317,93 +317,78 @@ public enum EffectType /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] Metal, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] OrangeCandy, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] OrangeWitness, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] Prismatic, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] SlowMetabolism, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] Spicy, /// /// . /// - // [Obsolete("Only availaible for Halloween or Christmas.")] + // [Obsolete("Only availaible for Halloween.")] SugarCrave, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] SugarHigh, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] SugarRush, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] TemporaryBypass, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] TraumatizedByEvil, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] WhiteCandy, /// /// . /// Scp1509Resurrected, - - /// - /// . - /// - FocusedVision, - - /// - /// . - /// - AnomalousRegeneration, - - /// - /// . - /// - AnomalousTarget, } } diff --git a/EXILED/Exiled.API/Enums/GlassType.cs b/EXILED/Exiled.API/Enums/GlassType.cs index fef4d59f44..85c068108f 100644 --- a/EXILED/Exiled.API/Enums/GlassType.cs +++ b/EXILED/Exiled.API/Enums/GlassType.cs @@ -84,10 +84,5 @@ public enum GlassType /// Represents the window in . /// GateAArmory, - - /// - /// Represents the window in - /// - HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/PrefabType.cs b/EXILED/Exiled.API/Enums/PrefabType.cs index 43936f1d80..6a52ce7995 100644 --- a/EXILED/Exiled.API/Enums/PrefabType.cs +++ b/EXILED/Exiled.API/Enums/PrefabType.cs @@ -417,47 +417,5 @@ public enum PrefabType [Prefab(213466224, "SCP-939 Ragdoll Halloween")] Scp939RagdollHalloween, - - [Prefab(689741320, "SCP-559 Cake")] - Scp559Cake, - - [Prefab(2657863153, "SCP-956")] - Scp956, - - [Prefab(1205960739, "SCP-2536 Tree")] - Scp2536, - - [Prefab(2102014206, "Snowpile")] - Snowpile, - - [Prefab(3401975113, "Scp018Projectile Christmas")] - Scp018ProjectileChristmas, - - [Prefab(3223468476, "SnowballProjectile")] - SnowballProjectile, - - [Prefab(296717882, "CoalPickup")] - CoalPickup, - - [Prefab(409273101, "TapePlayerPickup")] - Scp1507TapePickup, - - [Prefab(3971391978, "Scp021JPickup")] - Scp021JPickup, - - [Prefab(142820664, "CoalProjectile")] - CoalProjectile, - - [Prefab(2405470903, "Scp2536Projectile")] - Scp2536Projectile, - - [Prefab(1496232901, "SCP-173 Ragdoll Variant")] - Scp173RagdollChristmas, - - [Prefab(6069361, "SnowPoop - TantrumObj")] - SnowTantrum, - - [Prefab(3654754970, "SCP-1507 Ragdoll")] - Scp1507Ragdoll, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/ProjectileType.cs b/EXILED/Exiled.API/Enums/ProjectileType.cs index 2d95210924..a8072ed48e 100644 --- a/EXILED/Exiled.API/Enums/ProjectileType.cs +++ b/EXILED/Exiled.API/Enums/ProjectileType.cs @@ -51,21 +51,21 @@ public enum ProjectileType /// Coal. /// Used by . /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] Coal, /// /// SpecialCoal. /// Used by . /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] SpecialCoal, /// /// Snowball. /// Used by . /// - // [Obsolete("Only availaible for Christmas.")] + [Obsolete("Only availaible for Christmas.")] Snowball, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/RoomType.cs b/EXILED/Exiled.API/Enums/RoomType.cs index 6dceeea6e2..0b7737c193 100644 --- a/EXILED/Exiled.API/Enums/RoomType.cs +++ b/EXILED/Exiled.API/Enums/RoomType.cs @@ -353,10 +353,5 @@ public enum RoomType /// Heavy Containment Zone's straight hall room with lava. /// HczDss12 = HczIncineratorWayside, - - /// - /// Heavy Containment Zone's T-intersection with a ramp in it. - /// - HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/Side.cs b/EXILED/Exiled.API/Enums/Side.cs index 5accace2f3..5e9c063be7 100644 --- a/EXILED/Exiled.API/Enums/Side.cs +++ b/EXILED/Exiled.API/Enums/Side.cs @@ -52,10 +52,5 @@ public enum Side /// No team. Same as . /// None, - - /// - /// Contains and . Same as . - /// - Flamingos, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Exiled.API.csproj b/EXILED/Exiled.API/Exiled.API.csproj index 70f81bf0d1..31fe36e002 100644 --- a/EXILED/Exiled.API/Exiled.API.csproj +++ b/EXILED/Exiled.API/Exiled.API.csproj @@ -34,7 +34,6 @@ - diff --git a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs index 6fde63477d..95dfc33727 100644 --- a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs +++ b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs @@ -204,13 +204,6 @@ public static DamageType GetDamageType(DamageHandlerBase damageHandlerBase) Log.Warn($"{nameof(DamageTypeExtensions)}.{nameof(damageHandlerBase)}: No matching {nameof(DamageType)} for {nameof(UniversalDamageHandler)} with ID {translation.Id}, type will be reported as {DamageType.Unknown}. Report this to EXILED Devs."); return DamageType.Unknown; } - - case AttackerDamageHandler attackerDamageHandler: - { - if (Player.TryGet(attackerDamageHandler.Attacker, out Player attacker) && attacker.CurrentItem?.Type == ItemType.MarshmallowItem) - return DamageType.Marshmallow; - return DamageType.Unknown; - } } return DamageType.Unknown; diff --git a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs index 088438e085..c44a32362d 100644 --- a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs +++ b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs @@ -101,9 +101,6 @@ public static class EffectTypeExtension { EffectType.TraumatizedByEvil, typeof(TraumatizedByEvil) }, { EffectType.WhiteCandy, typeof(WhiteCandy) }, { EffectType.Scp1509Resurrected, typeof(Scp1509Resurrected) }, - { EffectType.FocusedVision, typeof(FocusedVision) }, - { EffectType.AnomalousRegeneration, typeof(AnomalousRegeneration) }, - { EffectType.AnomalousTarget, typeof(AnomalousTarget) }, #pragma warning restore CS0618 }); diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs index 3ba47fd9a8..605e6466c0 100644 --- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs +++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs @@ -17,7 +17,6 @@ namespace Exiled.API.Extensions using AdminToys; using AudioPooling; - using Cassie; using CustomPlayerEffects; using Exiled.API.Enums; using Exiled.API.Features.Items; @@ -513,12 +512,13 @@ public static void ResyncKeycardPickup(CustomKeycardPickup customKeycard) /// Same on 's isSubtitles. public static void PlayCassieAnnouncement(this Player player, string words, bool makeHold = false, bool makeNoise = true, bool isSubtitles = false) { - CassieAnnouncement announcement = new(new CassieTtsPayload(words, isSubtitles, makeHold), 0, makeNoise ? 1 : 0); - - // processes makeNoise - announcement.OnStartedPlaying(); - - announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); + foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) + { + if (controller != null) + { + SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), words, makeHold, makeNoise, isSubtitles); + } + } } /// @@ -533,12 +533,23 @@ public static void PlayCassieAnnouncement(this Player player, string words, bool /// Same on 's isSubtitles. public static void MessageTranslated(this Player player, string words, string translation, string customSubtitles, bool makeHold = false, bool makeNoise = true, bool isSubtitles = true) { - CassieAnnouncement announcement = new(new CassieTtsPayload(words, customSubtitles, makeHold), 0, makeNoise ? 1 : 0); + StringBuilder announcement = StringBuilderPool.Pool.Get(); - // processes makeNoise - announcement.OnStartedPlaying(); + string[] cassies = words.Split('\n'); + string[] translations = translation.Split('\n'); - announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); + for (int i = 0; i < cassies.Length; i++) + announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); + + string message = StringBuilderPool.Pool.ToStringReturn(announcement); + + foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) + { + if (controller != null) + { + SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), message, makeHold, makeNoise, isSubtitles, customSubtitles); + } + } } /// diff --git a/EXILED/Exiled.API/Extensions/RoleExtensions.cs b/EXILED/Exiled.API/Extensions/RoleExtensions.cs index db1a7c99a9..369910654a 100644 --- a/EXILED/Exiled.API/Extensions/RoleExtensions.cs +++ b/EXILED/Exiled.API/Extensions/RoleExtensions.cs @@ -70,7 +70,6 @@ public static class RoleExtensions Team.FoundationForces or Team.Scientists => Side.Mtf, Team.ChaosInsurgency or Team.ClassD => Side.ChaosInsurgency, Team.OtherAlive => Side.Tutorial, - Team.Flamingos => Side.Flamingos, _ => Side.None, }; @@ -81,13 +80,12 @@ public static class RoleExtensions /// . public static Team GetTeam(this RoleTypeId roleType) => roleType switch { - RoleTypeId.ChaosConscript or RoleTypeId.ChaosMarauder or RoleTypeId.ChaosRepressor or RoleTypeId.ChaosRifleman or RoleTypeId.ChaosFlamingo => Team.ChaosInsurgency, + RoleTypeId.ChaosConscript or RoleTypeId.ChaosMarauder or RoleTypeId.ChaosRepressor or RoleTypeId.ChaosRifleman => Team.ChaosInsurgency, RoleTypeId.Scientist => Team.Scientists, RoleTypeId.ClassD => Team.ClassD, - RoleTypeId.Scp049 or RoleTypeId.Scp939 or RoleTypeId.Scp0492 or RoleTypeId.Scp079 or RoleTypeId.Scp096 or RoleTypeId.Scp106 or RoleTypeId.Scp173 or RoleTypeId.Scp3114 or RoleTypeId.ZombieFlamingo=> Team.SCPs, - RoleTypeId.FacilityGuard or RoleTypeId.NtfCaptain or RoleTypeId.NtfPrivate or RoleTypeId.NtfSergeant or RoleTypeId.NtfSpecialist or RoleTypeId.NtfFlamingo => Team.FoundationForces, + RoleTypeId.Scp049 or RoleTypeId.Scp939 or RoleTypeId.Scp0492 or RoleTypeId.Scp079 or RoleTypeId.Scp096 or RoleTypeId.Scp106 or RoleTypeId.Scp173 or RoleTypeId.Scp3114 => Team.SCPs, + RoleTypeId.FacilityGuard or RoleTypeId.NtfCaptain or RoleTypeId.NtfPrivate or RoleTypeId.NtfSergeant or RoleTypeId.NtfSpecialist => Team.FoundationForces, RoleTypeId.Tutorial => Team.OtherAlive, - RoleTypeId.Flamingo or RoleTypeId.AlphaFlamingo => Team.Flamingos, _ => Team.Dead, }; @@ -133,7 +131,6 @@ public static bool TryGetRoleBase(this RoleTypeId roleType, out T roleBase) Team.ClassD or Team.ChaosInsurgency => LeadingTeam.ChaosInsurgency, Team.FoundationForces or Team.Scientists => LeadingTeam.FacilityForces, Team.SCPs => LeadingTeam.Anomalies, - Team.Flamingos => LeadingTeam.Flamingo, _ => LeadingTeam.Draw, }; diff --git a/EXILED/Exiled.API/Features/Camera.cs b/EXILED/Exiled.API/Features/Camera.cs index fa17a77540..fca5cbbc73 100644 --- a/EXILED/Exiled.API/Features/Camera.cs +++ b/EXILED/Exiled.API/Features/Camera.cs @@ -143,11 +143,6 @@ public class Camera : IWrapper, IWorldSpace ["GATE A ELEVATORS"] = CameraType.EzGateAElevators, ["GATE B INTERIOR"] = CameraType.EzGateBInterior, ["GATE B SIDE"] = CameraType.EzGateBSide, - ["GATE A STAIRWELL"] = CameraType.EzGateAStairwell, - ["GATE A UPPER"] = CameraType.EzGateAUpper, - ["LOADING BAY"] = CameraType.HczLoadingBay, - ["HCZ LOADING RAMP"] = CameraType.HczLoadingBayRamp, - ["STAIRWELL"] = CameraType.HczLoadingBayStairwell, // CustomCamera ["EZ ARM CAMERA TOY"] = CameraType.EzArmCameraToy, diff --git a/EXILED/Exiled.API/Features/Cassie.cs b/EXILED/Exiled.API/Features/Cassie.cs index 475e68ad4e..0730f9a5a9 100644 --- a/EXILED/Exiled.API/Features/Cassie.cs +++ b/EXILED/Exiled.API/Features/Cassie.cs @@ -7,19 +7,19 @@ namespace Exiled.API.Features { - using System; using System.Collections.Generic; using System.Linq; using System.Text; using Exiled.API.Features.Pools; - using global::Cassie; - using global::Cassie.Interpreters; + using MEC; + using PlayerRoles; + using PlayerStatsSystem; + using Respawning; - using Respawning.NamingRules; using CustomFirearmHandler = DamageHandlers.FirearmDamageHandler; using CustomHandlerBase = DamageHandlers.DamageHandlerBase; @@ -29,15 +29,20 @@ namespace Exiled.API.Features /// public static class Cassie { + /// + /// Gets the singleton. + /// + public static NineTailedFoxAnnouncer Announcer => NineTailedFoxAnnouncer.singleton; + /// /// Gets a value indicating whether C.A.S.S.I.E is currently announcing. Does not include decontamination or Alpha Warhead Messages. /// - public static bool IsSpeaking => CassieAnnouncementDispatcher.AllAnnouncements.Count != 0; + public static bool IsSpeaking => Announcer.queue.Count != 0; /// - /// Gets a of objects that C.A.S.S.I.E recognizes. + /// Gets a of objects that C.A.S.S.I.E recognizes. /// - public static IReadOnlyCollection VoiceLines => CassieAnnouncementDispatcher.AllAnnouncements; + public static IReadOnlyCollection VoiceLines => Announcer.voiceLines; /// /// Reproduce a non-glitched C.A.S.S.I.E message. @@ -47,7 +52,7 @@ public static class Cassie /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void Message(string message, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); + RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles); /// /// Reproduce a non-glitched C.A.S.S.I.E message with a possibility to custom the subtitles. @@ -59,7 +64,14 @@ public static void Message(string message, bool isHeld = false, bool isNoisy = t /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void MessageTranslated(string message, string translation, bool isHeld = false, bool isNoisy = true, bool isSubtitles = true) { - new CassieAnnouncement(new CassieTtsPayload(message, translation, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); + StringBuilder announcement = StringBuilderPool.Pool.Get(); + string[] cassies = message.Split('\n'); + string[] translations = translation.Split('\n'); + for (int i = 0; i < cassies.Length; i++) + announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); + + RespawnEffectsController.PlayCassieAnnouncement(announcement.ToString(), isHeld, isNoisy, isSubtitles); + StringBuilderPool.Pool.Return(announcement); } /// @@ -69,7 +81,7 @@ public static void MessageTranslated(string message, string translation, bool is /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void GlitchyMessage(string message, float glitchChance, float jamChance) => - new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue(); + Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance); /// /// Reproduce a non-glitched C.A.S.S.I.E message after a certain amount of seconds. @@ -80,7 +92,7 @@ public static void GlitchyMessage(string message, float glitchChance, float jamC /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void DelayedMessage(string message, float delay, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue()); + Timing.CallDelayed(delay, () => RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles)); /// /// Reproduce a glitchy C.A.S.S.I.E announcement after a certain period of seconds. @@ -90,53 +102,17 @@ public static void DelayedMessage(string message, float delay, bool isHeld = fal /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void DelayedGlitchyMessage(string message, float delay, float glitchChance, float jamChance) => - Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue()); - - /// - /// Calculates the duration of a C.A.S.S.I.E message. - /// - /// The message, which duration will be calculated. - /// An obsolete parameter. - /// Another obsolete parameter. - /// Duration (in seconds) of specified message. - [Obsolete("Please use CalculateDuration(string)", true)] - public static float CalculateDuration(string message, bool obsolete1, float obsolete2) => CalculateDuration(message); + Timing.CallDelayed(delay, () => Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance)); /// /// Calculates the duration of a C.A.S.S.I.E message. /// /// The message, which duration will be calculated. + /// Determines if a number won't be converted to its full pronunciation. + /// The speed of the message. /// Duration (in seconds) of specified message. - public static float CalculateDuration(string message) - { - if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) - { - return 0; - } - - float value = 0; - string[] lines = message.Split(' ', StringSplitOptions.RemoveEmptyEntries); - - CassiePlaybackModifiers modifiers = new(); - StringBuilder builder = StringBuilderPool.Pool.Get(); - - for (int i = 0; i < lines.Length; i++) - { - foreach (CassieInterpreter interpreter in CassieTtsAnnouncer.Interpreters) - { - bool halt; - foreach (CassieInterpreter.Result result in interpreter.GetResults(cassieLineDatabase, ref modifiers, lines[i], builder, out halt)) - { - value += (float)result.Modifiers.GetTimeUntilNextWord(result.Line); - } - - if (halt) - break; - } - } - - return value; - } + public static float CalculateDuration(string message, bool rawNumber = false, float speed = 1f) + => Announcer.CalculateDuration(message, rawNumber, speed); /// /// Converts a into a Cassie-Readable CONTAINMENTUNIT. @@ -144,16 +120,8 @@ public static float CalculateDuration(string message) /// . /// Unit Name. /// Containment Unit text. - public static string ConvertTeam(Team team, string unitName) => team switch - { - Team.FoundationForces when NamingRulesManager.TryGetNamingRule(team, out UnitNamingRule unitNamingRule) => "CONTAINMENTUNIT " + unitNamingRule.TranslateToCassie(unitName), - Team.FoundationForces => "CONTAINMENTUNIT UNKNOWN", - Team.ChaosInsurgency => "BY CHAOSINSURGENCY", - Team.Scientists => "BY SCIENCE PERSONNEL", - Team.ClassD => "BY CLASSD PERSONNEL", - Team.Flamingos => "BY SCP 1 5 0 7", - _ => "UNKNOWN", - }; + public static string ConvertTeam(Team team, string unitName) + => NineTailedFoxAnnouncer.ConvertTeam(team, unitName); /// /// Converts a number into a Cassie-Readable String. @@ -161,23 +129,7 @@ Team.FoundationForces when NamingRulesManager.TryGetNamingRule(team, out UnitNam /// Number to convert. /// A CASSIE-readable representing the number. public static string ConvertNumber(int num) - { - if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) - { - return string.Empty; - } - - NumberInterpreter numberInterpreter = (NumberInterpreter)CassieTtsAnnouncer.Interpreters.FirstOrDefault((CassieInterpreter x) => x is NumberInterpreter); - if (numberInterpreter == null) - { - return string.Empty; - } - - CassiePlaybackModifiers cassiePlaybackModifiers = default; - StringBuilder stringBuilder = new(); - numberInterpreter.GetResults(cassieLineDatabase, ref cassiePlaybackModifiers, num.ToString(), stringBuilder, out bool flag); - return stringBuilder.ToString(); - } + => NineTailedFoxAnnouncer.ConvertNumber(num); /// /// Announce a SCP Termination. @@ -185,7 +137,7 @@ public static string ConvertNumber(int num) /// SCP to announce termination of. /// HitInformation. public static void ScpTermination(Player scp, DamageHandlerBase info) - => CassieScpTerminationAnnouncement.AnnounceScpTermination(scp.ReferenceHub, info); + => NineTailedFoxAnnouncer.AnnounceScpTermination(scp.ReferenceHub, info); /// /// Announces the termination of a custom SCP name. @@ -215,14 +167,14 @@ public static void CustomScpTermination(string scpName, CustomHandlerBase info) /// /// Clears the C.A.S.S.I.E queue. /// - public static void Clear() => CassieAnnouncementDispatcher.ClearAll(); + public static void Clear() => RespawnEffectsController.ClearQueue(); /// /// Gets a value indicating whether the given word is a valid C.A.S.S.I.E word. /// /// The word to check. /// if the word is valid; otherwise, . - public static bool IsValid(string word) => CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase) ? cassieLineDatabase.AllLines.Any(line => line.ApiName.ToUpper() == word.ToUpper()) : false; + public static bool IsValid(string word) => Announcer.voiceLines.Any(line => line.apiName.ToUpper() == word.ToUpper()); /// /// Gets a value indicating whether the given sentence is all valid C.A.S.S.I.E word. diff --git a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs index fde6e9e00a..67b464474f 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs @@ -39,17 +39,11 @@ public CustomDamageHandler(Player target, BaseHandler baseHandler) if (Attacker is not null) { if (baseHandler is BaseScpDamageHandler) - { CustomBase = new ScpDamageHandler(target, baseHandler); - } + else if (Attacker.CurrentItem is not null && Attacker.CurrentItem.Type.IsWeapon() && baseHandler is BaseFirearmHandler) + CustomBase = new FirearmDamageHandler(Attacker.CurrentItem, target, baseHandler); else - { - Item item = Attacker.CurrentItem; - if (item is not null && item.Type.IsWeapon() && baseHandler is BaseFirearmHandler) - CustomBase = new FirearmDamageHandler(item, target, baseHandler); - else - CustomBase = new DamageHandler(target, Attacker); - } + CustomBase = new DamageHandler(target, Attacker); } else { diff --git a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs index 248e89452b..ec59d5ee5a 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs @@ -271,13 +271,6 @@ protected DamageType GetDamageType(BaseHandler damageHandler = null) FirearmType.FRMG0 => DamageType.Frmg0, _ => DamageType.Firearm }; - - case PlayerStatsSystem.AttackerDamageHandler attackerDamageHandler: - { - if (Player.TryGet(attackerDamageHandler.Attacker, out Player attacker) && attacker.CurrentItem?.Type == ItemType.MarshmallowItem) - return DamageType.Marshmallow; - return DamageType.Unknown; - } } return DamageType.Unknown; diff --git a/EXILED/Exiled.API/Features/Doors/Door.cs b/EXILED/Exiled.API/Features/Doors/Door.cs index a8163f207c..19718900a7 100644 --- a/EXILED/Exiled.API/Features/Doors/Door.cs +++ b/EXILED/Exiled.API/Features/Doors/Door.cs @@ -624,7 +624,6 @@ private DoorType GetDoorType() RoomType.HczEzCheckpointA => DoorType.CheckpointArmoryA, RoomType.HczEzCheckpointB => DoorType.CheckpointArmoryB, RoomType.EzGateA => DoorType.GateAArmory, - RoomType.HczLoadingBay => DoorType.HczLoadingBay, _ => DoorType.UnknownDoor, }, "Unsecured Pryable GateDoor" => Room?.Type switch diff --git a/EXILED/Exiled.API/Features/Effect.cs b/EXILED/Exiled.API/Features/Effect.cs index 426b68dcdc..f901966917 100644 --- a/EXILED/Exiled.API/Features/Effect.cs +++ b/EXILED/Exiled.API/Features/Effect.cs @@ -35,7 +35,7 @@ public Effect(StatusEffectBase statusEffectBase) if (!statusEffectBase.TryGetEffectType(out EffectType effect)) Log.Error($"EffectType not found please report to Exiled BugReport : {statusEffectBase}"); Type = effect; - Duration = statusEffectBase.TimeLeft; + Duration = statusEffectBase.Duration; Intensity = statusEffectBase.Intensity; IsEnabled = statusEffectBase.IsEnabled; } diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs index 8fb2688bb7..50a2538c64 100644 --- a/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs @@ -11,8 +11,9 @@ namespace Exiled.API.Features.Items.FirearmModules using Exiled.API.Features.Items.FirearmModules.Barrel; using Exiled.API.Features.Items.FirearmModules.Primary; + using InventorySystem.Items.Firearms.Modules; - using InventorySystem.Items.Firearms.Modules.Scp127; + using UnityEngine; /// @@ -65,12 +66,8 @@ public static Magazine Get(IAmmoContainerModule module) PumpActionModule pump => new PumpBarrelMagazine(pump), IPrimaryAmmoContainerModule primary => primary switch { + MagazineModule magazine => new NormalMagazine(magazine), CylinderAmmoModule cylinder => new CylinderMagazine(cylinder), - MagazineModule magazine => magazine switch - { - Scp127MagazineModule scp127MagazineModule => new Scp127Magazine(scp127MagazineModule), - _ => new NormalMagazine(magazine) - }, _ => null, }, _ => null, diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs deleted file mode 100644 index c3226169ea..0000000000 --- a/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs +++ /dev/null @@ -1,80 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.API.Features.Items.FirearmModules.Primary -{ - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Represents a normal magazine for SCP-127. - /// - public class Scp127Magazine : NormalMagazine - { - /// - /// Initializes a new instance of the class. - /// - /// - public Scp127Magazine(Scp127MagazineModule magazine) - : base(magazine) - { - MagazineModule = magazine; - } - - /// - public new Scp127MagazineModule MagazineModule { get; } - - /// - /// Gets or sets the kill bonus. - /// - public int KillBonus - { - get => MagazineModule.KillBonus; - set => MagazineModule.KillBonus = value; - } - - /// - /// Gets or sets the rank up bonus. - /// - public int RankUpBonus - { - get => MagazineModule.RankUpBonus; - set => MagazineModule.RankUpBonus = value; - } - - /// - /// Gets or sets all settings. - /// - public Scp127MagazineModule.RegenerationSettings[] RegenerationPerTier - { - get => MagazineModule._regenerationPerTier; - set => MagazineModule._regenerationPerTier = value; - } - - /// - /// Gets the current setting. - /// - public Scp127MagazineModule.RegenerationSettings ActiveSetting => MagazineModule.ActiveSettings; - - /// - /// Gets or sets a pause in bullets regeneration process. - /// - public float RemainingRegenPause - { - get => MagazineModule._remainingRegenPause; - set => MagazineModule._remainingRegenPause = value; - } - - /// - /// Gets or sets the amount of bullets that should be regenerated. - /// - public float RegenProgress - { - get => MagazineModule._regenProgress; - set => MagazineModule._regenProgress = value; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs index 89bb189c42..f9d8a74a0d 100644 --- a/EXILED/Exiled.API/Features/Items/Item.cs +++ b/EXILED/Exiled.API/Features/Items/Item.cs @@ -22,7 +22,6 @@ namespace Exiled.API.Features.Items using InventorySystem.Items.Firearms.Ammo; using InventorySystem.Items.Jailbird; using InventorySystem.Items.Keycards; - using InventorySystem.Items.MarshmallowMan; using InventorySystem.Items.MicroHID; using InventorySystem.Items.Pickups; using InventorySystem.Items.Radio; @@ -219,11 +218,7 @@ public static Item Get(ItemBase itemBase) return itemBase switch { - InventorySystem.Items.Firearms.Firearm firearm => firearm.ItemTypeId switch - { - ItemType.GunSCP127 => new Scp127(firearm), - _ => new Firearm(firearm), - }, + InventorySystem.Items.Firearms.Firearm firearm => new Firearm(firearm), KeycardItem keycard => keycard switch { ChaosKeycardItem chaosKeycardItem => new ChaosKeycard(chaosKeycardItem), @@ -261,7 +256,6 @@ public static Item Get(ItemBase itemBase) _ => new Throwable(throwable), }, Scp1509Item scp1509 => new Scp1509(scp1509), - MarshmallowItem marshmallow => new Marshmallow(marshmallow), _ => new(itemBase), }; } @@ -324,11 +318,7 @@ public static T Get(ushort serial) /// The created. This can be cast as a subclass. public static Item Create(ItemType type, Player owner = null) => type.GetTemplate() switch { - InventorySystem.Items.Firearms.Firearm => type switch - { - ItemType.GunSCP127 => new Scp127(), - _ => new Firearm(type), - }, + InventorySystem.Items.Firearms.Firearm => new Firearm(type), KeycardItem keycard => keycard switch { ChaosKeycardItem => new ChaosKeycard(type), @@ -366,7 +356,6 @@ public static T Get(ushort serial) _ => new Throwable(type, owner), }, Scp1509Item => new Scp1509(), - MarshmallowItem => new Marshmallow(type, owner), _ => new(type), }; diff --git a/EXILED/Exiled.API/Features/Items/Jailbird.cs b/EXILED/Exiled.API/Features/Items/Jailbird.cs index 4cc9a59c86..b68a3473c2 100644 --- a/EXILED/Exiled.API/Features/Items/Jailbird.cs +++ b/EXILED/Exiled.API/Features/Items/Jailbird.cs @@ -52,8 +52,8 @@ internal Jailbird() /// public float MeleeDamage { - get => Base.MeleeDamage; - set => Base.MeleeDamage = value; + get => Base._hitreg._damageMelee; + set => Base._hitreg._damageMelee = value; } /// @@ -61,8 +61,8 @@ public float MeleeDamage /// public float ChargeDamage { - get => Base._chargeDamage; - set => Base._chargeDamage = value; + get => Base._hitreg._damageCharge; + set => Base._hitreg._damageCharge = value; } /// @@ -70,8 +70,8 @@ public float ChargeDamage /// public float FlashDuration { - get => Base._flashedDuration; - set => Base._flashedDuration = value; + get => Base._hitreg._flashedDuration; + set => Base._hitreg._flashedDuration = value; } /// @@ -79,17 +79,17 @@ public float FlashDuration /// public float ConcussionDuration { - get => Base._concussionDuration; - set => Base._concussionDuration = value; + get => Base._hitreg._concussionDuration; + set => Base._hitreg._concussionDuration = value; } /// - /// Gets or sets the radius of the Jailbird's hit radius. + /// Gets or sets the radius of the Jailbird's hit register. /// public float Radius { - get => Base._hitregRadius; - set => Base._hitregRadius = value; + get => Base._hitreg._hitregRadius; + set => Base._hitreg._hitregRadius = value; } /// @@ -97,10 +97,10 @@ public float Radius /// public float TotalDamageDealt { - get => Base.TotalMeleeDamageDealt; + get => Base._hitreg.TotalMeleeDamageDealt; set { - Base.TotalMeleeDamageDealt = value; + Base._hitreg.TotalMeleeDamageDealt = value; Base._deterioration.RecheckUsage(); } } diff --git a/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs b/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs index bab50d19ce..8d8bdad39d 100644 --- a/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs +++ b/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs @@ -43,8 +43,7 @@ internal ChaosKeycard(ItemType type) /// /// Gets the this encapsulates. /// - /// Can be null, but shouldn't be during usage. - public SnakeEngine SnakeEngine => ChaosKeycardItem.SnakeSessions.TryGetValue(Serial, out SnakeEngine engine) ? engine : null; + public SnakeEngine SnakeEngine => Base._localEngine; /// /// Returns the Keycard in a human readable format. diff --git a/EXILED/Exiled.API/Features/Items/Marshmallow.cs b/EXILED/Exiled.API/Features/Items/Marshmallow.cs deleted file mode 100644 index 349fe342fb..0000000000 --- a/EXILED/Exiled.API/Features/Items/Marshmallow.cs +++ /dev/null @@ -1,102 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.API.Features.Items -{ - using CustomPlayerEffects; - using Exiled.API.Interfaces; - using InventorySystem.Items.MarshmallowMan; - using PlayerStatsSystem; - using UnityEngine; - - /// - /// A wrapper class for . - /// - public class Marshmallow : Item, IWrapper - { - /// - /// Initializes a new instance of the class. - /// - /// The base class. - public Marshmallow(MarshmallowItem itemBase) - : base(itemBase) - { - Base = itemBase; - } - - /// - /// Initializes a new instance of the class. - /// - /// The of the marshmallow item. - /// The owner of the marshmallow item. Leave for no owner. - internal Marshmallow(ItemType type, Player owner = null) - : base((MarshmallowItem)(owner ?? Server.Host).Inventory.CreateItemInstance(new(type, 0), false)) - { - } - - /// - /// Gets the that this class is encapsulating. - /// - public new MarshmallowItem Base { get; } - - /// - /// Gets a value indicating whether this marshmallow man is evil. - /// - /// See in regards to making a marshmallow evil. - public bool Evil => Base.EvilMode; - - /// - /// Gets or sets the of the marshmallow man that would be used if he was evil. - /// - public AhpStat.AhpProcess EvilAhpProcess - { - get => Base.EvilAHPProcess; - set - { - if (Evil && value is null) - return; - - Base.EvilAHPProcess = value; - } - } - - /// - /// Cackles for the owner even if they are not evil. - /// - /// How long until the player can cackle again (negative values do not affect current cooldown). - /// How long players near the marshmallow man get effected by . - public void Cackle(double cooldown = -1, float duration = 5) - { - if (cooldown >= 0) - Base._cackleCooldown.Trigger(cooldown); - - Base.ServerSendPublicRpc(writer => - { - writer.WriteByte(4); - Base._cackleCooldown.WriteCooldown(writer); - }); - - foreach (Player player in Player.List) - { - if (Vector3.Distance(player.Position, Owner.Position) <= 5F && player.CurrentItem is not Marshmallow { Evil: true }) - player.EnableEffect(duration); - } - } - - /// - /// Makes the owner of this marshmallow evil. You CANNOT undo this without resetting the player. - /// - /// The of the new evil player. - public void MakeEvil(AhpStat.AhpProcess evilProcess = null) - { - if (Evil) - return; - - Base.ReleaseEvil(evilProcess ?? EvilAhpProcess ?? Owner.GetModule().ServerAddProcess(450F, 450F, 0F, 1F, 0F, true)); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Items/Scp127.cs b/EXILED/Exiled.API/Features/Items/Scp127.cs deleted file mode 100644 index 2c71fbe4bb..0000000000 --- a/EXILED/Exiled.API/Features/Items/Scp127.cs +++ /dev/null @@ -1,274 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.API.Features.Items -{ - using System.Collections.Generic; - using System.Linq; - - using InventorySystem.Items.Firearms.Modules; - using InventorySystem.Items.Firearms.Modules.Scp127; - using UnityEngine; - - /// - /// Represents SCP-127. - /// - public class Scp127 : Firearm - { - #pragma warning disable SA1401 - /// - /// Custom amount of max HS. - /// - internal float? CustomHsMax; - #pragma warning restore SA1401 - - /// - /// Initializes a new instance of the class. - /// - /// - public Scp127(InventorySystem.Items.Firearms.Firearm itemBase) - : base(itemBase) - { - foreach (ModuleBase module in Base.Modules) - { - switch (module) - { - case Scp127HumeModule humeModule: - HumeModule = humeModule; - break; - case Scp127TierManagerModule tierManagerModule: - TierManagerModule = tierManagerModule; - break; - case Scp127VoiceLineManagerModule voiceLineManagerModule: - VoiceLineManagerModule = voiceLineManagerModule; - break; - } - } - } - - /// - /// Initializes a new instance of the class. - /// - internal Scp127() - : this((InventorySystem.Items.Firearms.Firearm)Server.Host.Inventory.CreateItemInstance(new(ItemType.GunSCP127, 0), false)) - { - } - - /// - /// Gets a collection of all active HS sessions. - /// - public static List ActiveHumeShieldSessions => Scp127HumeModule.ServerActiveSessions; - - /// - /// Gets the instance. - /// - public Scp127HumeModule HumeModule { get; } - - /// - /// Gets the instance. - /// - public Scp127TierManagerModule TierManagerModule { get; } - - /// - /// Gets the instance. - /// - public Scp127VoiceLineManagerModule VoiceLineManagerModule { get; } - - /// - /// Gets or sets the maximum amount of HS. - /// - /// If setter is used, after tier chance this value won't be edited automatically. - public float HsMax - { - get => CustomHsMax ?? HumeModule.HsMax; - set => CustomHsMax = value; - } - - /// - /// Gets or sets a shield regeneration rate. - /// - public float ShieldRegenRate - { - get => HumeModule.ShieldRegenRate; - set => HumeModule.ShieldRegenRate = value; - } - - /// - /// Gets or sets a shield decay time. - /// - public float ShieldDecayRate - { - get => HumeModule.ShieldDecayRate; - set => HumeModule.ShieldDecayRate = value; - } - - /// - /// Gets or sets a pause before HS starts regeneration after damage being taken. - /// - public float ShieldOnDamagePause - { - get => HumeModule.ShieldOnDamagePause; - set => HumeModule.ShieldOnDamagePause = value; - } - - /// - /// Gets or sets a delay before HS starts dropping after unequipment. - /// - public float UnequipDecayDelay - { - get => HumeModule.UnequipDecayDelay; - set => HumeModule.UnequipDecayDelay = value; - } - - /// - /// Gets or sets a HumeShield regeneration. - /// - public float HsRegeneration - { - get => HumeModule.HsRegeneration; - set => HumeModule.HsRegeneration = value; - } - - /// - /// Gets or sets an experience bonus for kill. - /// - public float KillBonus - { - get => TierManagerModule.KillBonus; - set => TierManagerModule.KillBonus = value; - } - - /// - /// Gets or sets an amount of passive experience increase. - /// - public float PassiveExpAmount - { - get => TierManagerModule.PassiveExpAmount; - set => TierManagerModule.PassiveExpAmount = value; - } - - /// - /// Gets or sets an interval of passive experience increase. - /// - public float PassiveExpInterval - { - get => TierManagerModule.PassiveExpInterval; - set => TierManagerModule.PassiveExpInterval = value; - } - - /// - /// Gets or sets a collection of all tier thresholds. - /// - public Scp127TierManagerModule.TierThreshold[] TierThresholds - { - get => TierManagerModule.Thresholds; - set => TierManagerModule.Thresholds = value; - } - - /// - /// Gets or sets current tier. - /// - public Scp127Tier CurrentTier - { - get => TierManagerModule.CurTier; - set => TierManagerModule.CurTier = value; - } - - /// - /// Gets or sets the current experience amount. - /// - public float Experience - { - get => TierManagerModule.ServerExp; - set => TierManagerModule.ServerExp = value; - } - - /// - /// Gets the instance record. - /// - public Scp127TierManagerModule.InstanceRecord InstanceRecord => Scp127TierManagerModule.GetRecord(Serial); - - /// - /// Gets the Owner stats. - /// - public Scp127TierManagerModule.OwnerStats OwnerStats => Scp127TierManagerModule.GetStats(Base); - - /// - /// Gets or sets all Voice Triggers. - /// - public Scp127VoiceTriggerBase[] VoiceTriggers - { - get => VoiceLineManagerModule._foundTriggers; - set => VoiceLineManagerModule._foundTriggers = value; - } - - /// - /// Gets a collection of players that are friends with this SCP-127. - /// - public IEnumerable Friends - { - get - { - if (!Scp127VoiceLineManagerModule.FriendshipMemory.TryGetValue(Serial, out HashSet uintSet)) - return null; - - return uintSet.Select(Player.Get); - } - } - - /// - /// Increases experience. - /// - /// Amount to add. - public void IncreaseExperience(float amount) => TierManagerModule.ServerIncreaseExp(Base, amount); - - /// - /// Sets owner stats. - /// - /// New experience amount. - public void SetOwnerStats(float exp) => TierManagerModule.ServerSetStats(exp); - - /// - /// Sends tier stats. - /// - /// New tier. - /// New progress. - public void SendTierStats(Scp127Tier tier, byte progress) => TierManagerModule.ServerSendStats(Serial, Owner.ReferenceHub, tier, progress); - - /// - /// Tries to play voice line. - /// - /// Voice line to play. - /// Priority of the play. - /// true if voice line has been played successfully. Otherwise, false. - public bool TryPlayVoiceLine(Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority priority = Scp127VoiceTriggerBase.VoiceLinePriority.Normal) - { - if (!VoiceLineManagerModule.TryFindVoiceLine(voiceLine, out Scp127VoiceTriggerBase triggerBase, out AudioClip audioClip)) - return false; - - VoiceLineManagerModule.ServerSendVoiceLine(triggerBase, null, audioClip, (byte)priority); - return true; - } - - /// - /// Checks if this instance of SCP-127 and have friendship. - /// - /// Target to check. - /// true if this instance of SCP-127 and have friendship. Otherwise, false. - public bool HasFriendship(Player player) => Scp127VoiceLineManagerModule.HasFriendship(Serial, player.ReferenceHub); - - /// - /// Adds player as a friend. - /// - /// Target to be added. - public void AddFriend(Player player) - { - HashSet uints = Scp127VoiceLineManagerModule.FriendshipMemory.GetOrAddNew(Serial); - uints.Add(player.NetId); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Lift.cs b/EXILED/Exiled.API/Features/Lift.cs index d191cd6764..469a33bd22 100644 --- a/EXILED/Exiled.API/Features/Lift.cs +++ b/EXILED/Exiled.API/Features/Lift.cs @@ -47,7 +47,6 @@ public class Lift : IWrapper, IWorldSpace internal Lift(ElevatorChamber elevator) { Base = elevator; - ElevatorAutoReturn = elevator.GetComponent(); ElevatorChamberToLift.Add(elevator, this); internalDoorsList.AddRange(Elevator.AllElevatorDoors[Group]); @@ -74,12 +73,6 @@ internal Lift(ElevatorChamber elevator) /// public ElevatorChamber Base { get; } - /// - /// Gets the base . - /// - /// Would be null for any elevator that do not used . - public ElevatorAutoReturn ElevatorAutoReturn { get; } - /// /// Gets a value of the internal doors list. /// diff --git a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs index eaaf77cb7a..0494d2e966 100644 --- a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs @@ -123,11 +123,11 @@ protected override void InitializeProperties(ItemBase itemBase) base.InitializeProperties(itemBase); if (itemBase is JailbirdItem jailbirdItem) { - MeleeDamage = jailbirdItem.MeleeDamage; - ChargeDamage = jailbirdItem._chargeDamage; - FlashDuration = jailbirdItem._flashedDuration; - ConcussionDuration = jailbirdItem._concussionDuration; - Radius = Radius; + MeleeDamage = jailbirdItem._hitreg._damageMelee; + ChargeDamage = jailbirdItem._hitreg._damageCharge; + FlashDuration = jailbirdItem._hitreg._flashedDuration; + ConcussionDuration = jailbirdItem._hitreg._concussionDuration; + Radius = jailbirdItem._hitreg._hitregRadius; } } } diff --git a/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs b/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs index 935bc636ca..b11c1cb0e9 100644 --- a/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs @@ -15,7 +15,7 @@ namespace Exiled.API.Features.Pickups using BaseScp1509 = InventorySystem.Items.Scp1509.Scp1509Pickup; /// - /// A wrapper class for a Scp1509 pickup. + /// A wrapper class for a Radio pickup. /// public class Scp1509Pickup : Pickup, IWrapper { diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 956fcf7f23..a61d640a84 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -648,7 +648,7 @@ public ScpSpawnPreferences.SpawnPreferences ScpPreferences /// /// Gets a value indicating whether the player is reloading a weapon. /// - public bool IsReloading => CurrentItem is Firearm firearm && firearm.IsReloading; + public bool IsReloading => CurrentItem is Firearm firearm && !firearm.IsReloading; /// /// Gets a value indicating whether the player is aiming with a weapon. @@ -1982,24 +1982,10 @@ public void SetRank(string name, UserGroup group) ReferenceHub.serverRoles.SetGroup(group, false, false); } - ServerStatic.PermissionsHandler.Members[UserId] = name; - } - - /// - /// If the rank(group) exists in the remote admin config, it will assign it to the player. - /// - /// The rank name to be set. - /// if the rank(group) was found and successfully assigned, otherwise. - public bool TrySetRank(string name) - { - if (ServerStatic.PermissionsHandler.Groups.TryGetValue(name, out UserGroup userGroup)) - { - ReferenceHub.serverRoles.SetGroup(userGroup, false, false); + if (ServerStatic.PermissionsHandler.Members.ContainsKey(UserId)) ServerStatic.PermissionsHandler.Members[UserId] = name; - return true; - } - - return false; + else + ServerStatic.PermissionsHandler.Members.Add(UserId, name); } /// @@ -2043,21 +2029,6 @@ public void Broadcast(Broadcast broadcast, bool shouldClearPrevious = false) Broadcast(broadcast.Duration, broadcast.Content, broadcast.Type, shouldClearPrevious); } - /// - /// Send an to the player. - /// - /// The to be broadcasted. - /// if Cassie failed to play it or it's play nothing, otherwise it's return the duration of the annoucement. - public float CassieAnnouncement(global::Cassie.CassieAnnouncement cassieAnnouncement) - { - global::Cassie.CassieAnnouncementDispatcher.CurrentAnnouncement.OnStartedPlaying(); - global::Cassie.CassieTtsPayload payload = cassieAnnouncement.Payload; - if (!global::Cassie.CassieTtsAnnouncer.TryPlay(payload, out float totalduration)) - return 0; - payload.SendToHubsConditionally(x => x == ReferenceHub); - return totalduration; - } - /// /// Drops an item from the player's inventory. /// @@ -2090,12 +2061,10 @@ public void DropItem(Item item, bool isThrown = false) /// Dropped item's . public Pickup DropHeldItem() { - Item item = CurrentItem; - - if (item is null) + if (CurrentItem is null) return null; - return DropItem(item); + return DropItem(CurrentItem); } /// @@ -3480,7 +3449,10 @@ public void SyncEffect(Effect effect) { if (effect.IsEnabled) { - EnableEffect(effect.Type, effect.Intensity, effect.Duration, effect.AddDurationIfActive); + EnableEffect(effect.Type, effect.Duration, effect.AddDurationIfActive); + + if (effect.Intensity > 0) + ChangeEffectIntensity(effect.Type, effect.Intensity, effect.Duration); } } @@ -3608,7 +3580,8 @@ public void ChangeEffectIntensity(byte intensity, float duration = 0) { if (ReferenceHub.playerEffectsController.TryGetEffect(out T statusEffect)) { - statusEffect.ServerSetState(intensity, duration, false); + statusEffect.Intensity = intensity; + statusEffect.ServerChangeDuration(duration, true); } } @@ -3622,7 +3595,8 @@ public void ChangeEffectIntensity(EffectType type, byte intensity, float duratio { if (TryGetEffect(type, out StatusEffectBase statusEffect)) { - statusEffect.ServerSetState(intensity, duration, false); + statusEffect.Intensity = intensity; + statusEffect.ServerChangeDuration(duration, false); } } diff --git a/EXILED/Exiled.API/Features/Recontainer.cs b/EXILED/Exiled.API/Features/Recontainer.cs index dbc31a35bf..17f59c97d5 100644 --- a/EXILED/Exiled.API/Features/Recontainer.cs +++ b/EXILED/Exiled.API/Features/Recontainer.cs @@ -7,7 +7,6 @@ namespace Exiled.API.Features { - using System; using System.Collections.Generic; using System.Linq; @@ -34,8 +33,7 @@ public static class Recontainer /// /// Gets a value indicating whether the C.A.S.S.I.E is currently busy. /// - [Obsolete("Use Cassie.IsSpeaking instead")] - public static bool IsCassieBusy => Cassie.IsSpeaking; + public static bool IsCassieBusy => Base.CassieBusy; /// /// Gets a value about how many generator have been activated. @@ -63,8 +61,11 @@ public static bool IsContainmentZoneLocked /// /// Gets or sets the delay to wait before overcharging. /// - [Obsolete("Will be removed in Exiled 10, patch the Cassie079RecontainAnnouncement ctor if you need this functionality")] - public static float OverchargeDelay { get; set; } + public static float OverchargeDelay + { + get => Base._activationDelay; + set => Base._activationDelay = value; + } /// /// Gets or sets the lockdown duration. @@ -187,7 +188,7 @@ public static bool IsContainmentSequenceSuccessful /// /// The announcement to play. /// The glitchy multiplier. - public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, false, false, null); + public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, glitchyMultiplier); /// /// Begins the overcharge procedure. @@ -198,6 +199,7 @@ public static void BeginOvercharge(bool endOvercharge = true) Base.BeginOvercharge(); if (endOvercharge) { + Base._delayStopwatch.Stop(); Base._unlockStopwatch.Start(); } } @@ -226,7 +228,7 @@ public static void BeginOvercharge(bool endOvercharge = true) /// /// Begins the recontainment procedure. /// - public static void Recontain() => Base.Recontain(false); + public static void Recontain() => Base.Recontain(); /// /// Refreshes the activator. diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs index 9a1156833e..2b0d75cf00 100644 --- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs +++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs @@ -300,30 +300,6 @@ public BasicRagdoll Ragdoll /// public SpectatableModuleBase SpectatableModuleBase => FirstPersonController.SpectatorModule; - /// - /// Tries to get the of a specified bone. - /// - /// The bone to get the of. - /// - /// When this method returns, contains the of the specified bone, if found; - /// otherwise, null. - /// - /// true if the bone transform was found; otherwise, false. - public bool TryGetBoneTransform(HumanBodyBones bone, out Transform boneTransform) - { - boneTransform = null; - - if (Model is not AnimatedCharacterModel animatedModel) - return false; - - Animator animator = animatedModel.Animator; - if (animator == null || animator.avatar == null || !animator.avatar.isValid || !animator.avatar.isHuman) - return false; - - boneTransform = animator.GetBoneTransform(bone); - return boneTransform != null; - } - /// /// Resets the 's stamina. /// diff --git a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs index 6283226eb4..1c015e2ff0 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs @@ -271,7 +271,8 @@ public void Attack(Player player) else { cardiacArrest.SetAttacker(AttackAbility.Owner); - cardiacArrest.ServerSetState(1, AttackAbility._statusEffectDuration, false); + cardiacArrest.Intensity = 1; + cardiacArrest.ServerChangeDuration(AttackAbility._statusEffectDuration, false); } SenseAbility.OnServerHit(AttackAbility._target); diff --git a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs index 6e78b6c662..a59e699ac9 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs @@ -16,8 +16,6 @@ namespace Exiled.API.Features.Roles using PlayerRoles.PlayableScps.Scp096; using PlayerRoles.Subroutines; - using UnityEngine; - using Scp096GameRole = PlayerRoles.PlayableScps.Scp096.Scp096Role; /// @@ -141,20 +139,6 @@ internal Scp096Role(Scp096GameRole baseRole) /// public bool AttackPossible => AttackAbility.AttackPossible; - /// - /// Gets the head transform of SCP-096's character model. - /// - public Transform HeadTransform - { - get - { - if (Model is not Scp096CharacterModel scp96AnimatedCharacterModel) - return null; - - return scp96AnimatedCharacterModel.Head; - } - } - /// /// Gets or sets the Charge Ability Cooldown. /// @@ -322,4 +306,4 @@ public void Charge(float cooldown = 1f) /// The Spawn Chance. public float GetSpawnChance(List alreadySpawned) => Base.GetSpawnChance(alreadySpawned); } -} +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs b/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs index 170bda116a..a4c9ba78cf 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs @@ -20,7 +20,7 @@ namespace Exiled.API.Features.Roles /// /// Defines a role that represents SCP-1507. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class Scp1507Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp { /// diff --git a/EXILED/Exiled.API/Features/Room.cs b/EXILED/Exiled.API/Features/Room.cs index 846a76509c..a81a24173f 100644 --- a/EXILED/Exiled.API/Features/Room.cs +++ b/EXILED/Exiled.API/Features/Room.cs @@ -506,7 +506,6 @@ private static RoomType FindType(GameObject gameObject) "HCZ_ChkpB" => RoomType.HczElevatorB, "HCZ_127" => RoomType.Hcz127, "HCZ_ServerRoom" => RoomType.HczServerRoom, - "HCZ_Intersection_Ramp" => RoomType.HczLoadingBay, "EZ_GateA" => RoomType.EzGateA, "EZ_GateB" => RoomType.EzGateB, "EZ_ThreeWay" => RoomType.EzTCross, diff --git a/EXILED/Exiled.API/Features/Scp559.cs b/EXILED/Exiled.API/Features/Scp559.cs index d05702b351..08fc899047 100644 --- a/EXILED/Exiled.API/Features/Scp559.cs +++ b/EXILED/Exiled.API/Features/Scp559.cs @@ -18,7 +18,7 @@ namespace Exiled.API.Features /// /// Represents a cake. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class Scp559 : IWrapper, IPosition { /// @@ -50,34 +50,20 @@ public Scp559(Scp559Cake cakeBase) /// /// Gets a with spawnpoint in rooms. /// - public static Dictionary SpawnPositions { get; } = Scp559Spawnpoint.InstancesPerRoom.ToDictionary(kvp => kvp.Key.Name, kvp => - { - Transform roomTransform = kvp.Key.transform; - Transform spawnTransform = kvp.Value.transform; - - Vector3 localPos = roomTransform.InverseTransformPoint(spawnTransform.position); - - return new Vector4(localPos.x, localPos.y, localPos.z, spawnTransform.eulerAngles.y); - }); + public static Dictionary SpawnPositions => Scp559Cake.Spawnpoints; /// /// Gets the list of all available spawnpoints. /// - public static List AvailableSpawnpoints => Scp559Cake.PossibleSpawnpoints.Select(spawnpoint => - { - Transform t = spawnpoint.transform; - return new Vector4(t.position.x, t.position.y, t.position.z, t.eulerAngles.y); - }).ToList(); + public static List AvailableSpawnpoints => Scp559Cake.PossiblePositions; /// /// Gets or sets offset for spawning near pedestals. /// public static Vector3 PedestalOffset { - get => new(0, -Scp559Spawnpoint.PedestalHeight, 0); - - [Obsolete("Setter no longer works")] - set { } + get => Scp559Cake.PedestalOffset; + set => Scp559Cake.PedestalOffset.Set(value.x, value.y, value.z); } /// diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs index 825cfb3566..96b8311fdf 100644 --- a/EXILED/Exiled.API/Features/Server.cs +++ b/EXILED/Exiled.API/Features/Server.cs @@ -111,27 +111,7 @@ public static string Name /// /// Gets the actual ticks per second of the server. /// - public static double Tps - { - get - { - double delta = Time.deltaTime; - - if (delta <= 0) - return MaxTps; - - double tps = 1d / delta; - - tps = Math.Min(tps, MaxTps); - - return tps; - } - } - - /// - /// Gets the average ticks per second of the server. - /// - public static double SmoothTps => Math.Round(1f / Time.smoothDeltaTime); + public static double Tps => Math.Round(1f / Time.smoothDeltaTime); /// /// Gets or sets the max ticks per second of the server. diff --git a/EXILED/Exiled.API/Features/Waves/TimedWave.cs b/EXILED/Exiled.API/Features/Waves/TimedWave.cs index 6e9a5c55bf..8856727c58 100644 --- a/EXILED/Exiled.API/Features/Waves/TimedWave.cs +++ b/EXILED/Exiled.API/Features/Waves/TimedWave.cs @@ -193,13 +193,13 @@ public static List GetTimedWaves() /// Plays the announcement for this wave. /// /// Wave must implement . - public void PlayAnnouncement() => Announcement?.PlayAnnouncement([], Base as IAnnouncedWave); + public void PlayAnnouncement() => Announcement?.PlayAnnouncement(new()); /// /// Plays the announcement for this wave. /// /// Wave must implement . /// The list of Player to spawn. - public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList(), Base as IAnnouncedWave); + public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList()); } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Window.cs b/EXILED/Exiled.API/Features/Window.cs index 2d327ff0c4..e5a1624e0d 100644 --- a/EXILED/Exiled.API/Features/Window.cs +++ b/EXILED/Exiled.API/Features/Window.cs @@ -231,7 +231,6 @@ public void DamageWindow(float amount, DamageHandlerBase handler) RoomType.HczEzCheckpointB => GlassType.HczEzCheckpointB, RoomType.EzGateA when Base.name[7] == '5' => GlassType.GateAArmory, RoomType.EzGateA => GlassType.GateAPit, - RoomType.HczLoadingBay => GlassType.HczLoadingBay, _ => GlassType.Unknown, }, "Window" => Room?.Type switch diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs index 182f47155e..fa39569e0a 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs @@ -1013,6 +1013,15 @@ private void OnInternalOwnerHandcuffing(HandcuffingEventArgs ev) continue; OnOwnerHandcuffing(new OwnerHandcuffingEventArgs(item, ev)); + + if (!ev.IsAllowed) + continue; + + ev.Target.RemoveItem(item); + + TrackedSerials.Remove(item.Serial); + + Spawn(ev.Target, item, ev.Target); } } diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index afce01ccdf..f29e2d525c 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -790,12 +790,6 @@ public bool TryAddFriendlyFire(Dictionary ffRules, bool overw return true; } - /// - /// Returns the CustomRole in a human-readable format. - /// - /// A string containing CustomRole-related data. - public override string ToString() => $"{Name} ({Id})"; - /// /// Tries to register this role. /// diff --git a/EXILED/Exiled.CustomRoles/Commands/Get.cs b/EXILED/Exiled.CustomRoles/Commands/Get.cs deleted file mode 100644 index 7d96d5f6b4..0000000000 --- a/EXILED/Exiled.CustomRoles/Commands/Get.cs +++ /dev/null @@ -1,123 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.CustomRoles.Commands -{ - using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Linq; - using System.Text; - - using CommandSystem; - using Exiled.API.Extensions; - using Exiled.API.Features; - using Exiled.API.Features.Pools; - using Exiled.CustomRoles.API; - using Exiled.CustomRoles.API.Features; - using Exiled.Permissions.Extensions; - using HarmonyLib; - - /// - /// The command to get specified player(s) current custom roles. - /// - internal sealed class Get : ICommand - { - private Get() - { - } - - /// - /// Gets the command instance. - /// - public static Get Instance { get; } = new(); - - /// - public string Command => "get"; - - /// - public string[] Aliases { get; } = Array.Empty(); - - /// - public string Description => "Gets the specified player(s)' current custom role(s)."; - - /// - public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) - { - if (!sender.CheckPermission("customroles.get")) - { - response = "Permission Denied, required: customroles.get"; - return false; - } - - List players = ListPool.Pool.Get(); - - if (arguments.Count > 0) - { - string identifier = string.Join(" ", arguments); - - switch (identifier.ToLower()) - { - case "*": - case "all": - players.AddRange(Player.List); - break; - default: - players.AddRange(Player.GetProcessedData(arguments)); - break; - } - - if (players.IsEmpty()) - { - if (arguments.Count > 0 || !Player.TryGet(sender, out Player player)) - { - response = $"Player not found: {identifier}"; - return false; - } - - players.Add(player); - } - } - else - { - response = "get "; - return false; - } - - StringBuilder builder = StringBuilderPool.Pool.Get(); - - builder.AppendLine(); - builder.AppendLine("====================== Custom Roles ======================"); - - foreach (Player target in players) - { - ReadOnlyCollection roles = target.GetCustomRoles(); - builder.Append((target.DisplayNickname + (target.HasCustomName ? $" ({target.Nickname})" : string.Empty)).PadRight(30 + (target.HasCustomName ? 23 : 0))); - builder.Append(" "); - builder.Append($"({target.Id})".PadRight(5)); - if (roles.IsEmpty()) - { - builder.AppendLine(" | No Custom Role"); - } - else - { - // builder.Append($" | [{string.Join(", ", roles.Select(role => $"{role}"))}]"); - builder.Append(" | ["); - builder.Append(string.Join(", ", roles.Select(role => $"{role}"))); - builder.AppendLine("]"); - } - } - - builder.AppendLine("=========================================================="); - - ListPool.Pool.Return(players); - - response = StringBuilderPool.Pool.ToStringReturn(builder); - return true; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.CustomRoles/Commands/Give.cs b/EXILED/Exiled.CustomRoles/Commands/Give.cs index 9666bff990..2f74b46498 100644 --- a/EXILED/Exiled.CustomRoles/Commands/Give.cs +++ b/EXILED/Exiled.CustomRoles/Commands/Give.cs @@ -83,7 +83,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s string identifier = string.Join(" ", arguments.Skip(1)); - switch (identifier.ToLower()) + switch (identifier) { case "*": case "all": diff --git a/EXILED/Exiled.CustomRoles/Commands/Parent.cs b/EXILED/Exiled.CustomRoles/Commands/Parent.cs index fd42b5e497..f64facabec 100644 --- a/EXILED/Exiled.CustomRoles/Commands/Parent.cs +++ b/EXILED/Exiled.CustomRoles/Commands/Parent.cs @@ -41,13 +41,12 @@ public override void LoadGeneratedCommands() RegisterCommand(Give.Instance); RegisterCommand(Info.Instance); RegisterCommand(List.List.Instance); - RegisterCommand(Get.Instance); } /// protected override bool ExecuteParent(ArraySegment arguments, ICommandSender sender, out string response) { - response = "Invalid subcommand! Available: give, info, list, get"; + response = "Invalid subcommand! Available: give, info, list"; return false; } } diff --git a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj index cd1a8b4769..78b2030580 100644 --- a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj +++ b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj @@ -49,4 +49,4 @@ if [[ ! -z "$EXILED_DEV_REFERENCES" ]]; then cp "$(OutputPath)$(AssemblyName).dll" "$EXILED_DEV_REFERENCES/Plugins/"; fi - \ No newline at end of file + diff --git a/EXILED/Exiled.Events/Commands/TpsCommand.cs b/EXILED/Exiled.Events/Commands/TpsCommand.cs index 14c0def05e..722de3b61e 100644 --- a/EXILED/Exiled.Events/Commands/TpsCommand.cs +++ b/EXILED/Exiled.Events/Commands/TpsCommand.cs @@ -15,6 +15,7 @@ namespace Exiled.Events.Commands /// /// Command for showing current server TPS. /// + [CommandHandler(typeof(RemoteAdminCommandHandler))] [CommandHandler(typeof(GameConsoleCommandHandler))] public class TpsCommand : ICommand { @@ -30,7 +31,7 @@ public class TpsCommand : ICommand /// public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) { - double diff = Server.SmoothTps / Server.MaxTps; + double diff = Server.Tps / Server.MaxTps; string color = diff switch { > 0.9 => "green", @@ -38,7 +39,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s _ => "red" }; - response = $"{Server.SmoothTps}/{Server.MaxTps}"; + response = $"{Server.Tps}/{Server.MaxTps}"; return true; } } diff --git a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs index abd2f4877f..a8b986c171 100644 --- a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs @@ -7,70 +7,39 @@ namespace Exiled.Events.EventArgs.Cassie { - using System; - using System.Text; - - using Exiled.API.Features.Pools; - using global::Cassie; using Interfaces; - using Subtitles; /// /// Contains all the information after sending a C.A.S.S.I.E. message. /// public class SendingCassieMessageEventArgs : IDeniableEvent { - private readonly CassieAnnouncement announcement; - private readonly CassieTtsPayload payload; - - private string customSubtitles; - private float glitchScale; - /// /// Initializes a new instance of the class. /// - /// The announcement to populate all properties from. - /// - /// + /// + /// + /// + /// + /// + /// + /// + /// /// - public SendingCassieMessageEventArgs(CassieAnnouncement annc, bool isAllowed = true) + /// + /// + /// + /// + /// + /// + /// Indicates whether the event can be executed. + public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise, bool customAnnouncement, string customSubtitles, bool isAllowed = true) { - announcement = annc; - payload = annc.Payload; - - Words = payload.Content; - switch (payload.SubtitleSource) - { - case CassieTtsPayload.SubtitleMode.None: - case CassieTtsPayload.SubtitleMode.Automatic: - CustomSubtitles = string.Empty; - break; - case CassieTtsPayload.SubtitleMode.Custom: - CustomSubtitles = payload._customSubtitle; - break; - case CassieTtsPayload.SubtitleMode.FromTranslation: - StringBuilder builder = StringBuilderPool.Pool.Get(); - SubtitleController controller = SubtitleController.Singleton; - - foreach (SubtitlePart part in payload._subtitleMessage.SubtitleParts) - { - Subtitle subtitle = controller.Subtitles[part.Subtitle]; - builder.Append(controller.GetTranslation(subtitle)); - } - - CustomSubtitles = StringBuilderPool.Pool.ToStringReturn(builder); - - break; - default: - CustomSubtitles = string.Empty; - break; - } - - MakeHold = payload.PlayBackground; - GlitchScale = annc.GlitchScale; - MakeNoise = annc.GlitchScale is not 0; - SubtitleSource = payload.SubtitleSource; - + Words = words; + CustomSubtitles = customSubtitles; + MakeHold = makeHold; + MakeNoise = makeNoise; + IsCustomAnnouncement = customAnnouncement; IsAllowed = isAllowed; } @@ -82,38 +51,13 @@ public SendingCassieMessageEventArgs(CassieAnnouncement annc, bool isAllowed = t /// /// Gets or sets the message subtitles. /// - public string CustomSubtitles - { - get => customSubtitles; - set - { - if (customSubtitles != value) - SubtitleSource = CassieTtsPayload.SubtitleMode.Custom; - - customSubtitles = value; - } - } + public string CustomSubtitles { get; set; } /// /// Gets or sets a value indicating whether the message should be held. /// public bool MakeHold { get; set; } - /// - /// Gets or sets a value controlling how glitchy this CASSIE message is. - /// - public float GlitchScale - { - get => glitchScale; - set - { - if (!MakeNoise && value is not 0) - MakeNoise = true; - - glitchScale = value; - } - } - /// /// Gets or sets a value indicating whether the message should make noise. /// @@ -125,50 +69,8 @@ public float GlitchScale public bool IsAllowed { get; set; } /// - /// Gets or sets a value indicating whether the event can be executed. + /// Gets or sets a value indicating whether the message can be sent. /// - [Obsolete("Useless and will be removed in Exiled 10.")] public bool IsCustomAnnouncement { get; set; } - - /// - /// Gets or sets a value indicating where the subtitles for this message came from. - /// - public CassieTtsPayload.SubtitleMode SubtitleSource { get; set; } - - /// - /// Gets a consisting of all properties in this event. - /// - public CassieAnnouncement Announcement - { - get - { - CassieTtsPayload newPayload; - - // I love readonly fields :) - if (SubtitleSource is CassieTtsPayload.SubtitleMode.FromTranslation) - { - newPayload = new CassieTtsPayload(Words, MakeHold, payload._subtitleMessage.SubtitleParts); - } - else - { - if (SubtitleSource is CassieTtsPayload.SubtitleMode.Automatic) - newPayload = new CassieTtsPayload(Words, true, MakeHold); - else - newPayload = new CassieTtsPayload(Words, CustomSubtitles, MakeHold); - } - - return announcement switch - { - CassieScpTerminationAnnouncement => - - // this is disabled via patch b/c termination messages are not modifiable at the stage the SendCassieMessage patch is in. - throw new InvalidOperationException("SendCassieMessage was called for a SCP termination message!"), - - CassieWaveAnnouncement waveAnnc => new CassieWaveAnnouncement(waveAnnc.Wave, newPayload), - Cassie079RecontainAnnouncement recontainAnnc => new Cassie079RecontainAnnouncement(recontainAnnc._callback, false, newPayload), - _ => new CassieAnnouncement(newPayload, 0, GlitchScale / (API.Features.Warhead.IsDetonated ? 2F : 1F) * (MakeNoise ? 1F : 0F)), - }; - } - } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs deleted file mode 100644 index fdd41cef5b..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Interfaces -{ - using Exiled.API.Features.Items; - - /// - /// Represents all events related to the marshmallow man. - /// - public interface IMarshmallowEvent : IItemEvent - { - /// - /// Gets the marshmallow item related to this event. - /// - public Marshmallow Marshmallow { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs deleted file mode 100644 index 616ad8f3e5..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Interfaces -{ - /// - /// Represents all events related to SCP-127. - /// - public interface IScp127Event : IItemEvent - { - /// - /// Gets the SCP-127 instance, related to this event. - /// - public API.Features.Items.Scp127 Scp127 { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs index acb2463878..1d6dcf3add 100644 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs @@ -14,7 +14,7 @@ namespace Exiled.Events.EventArgs.Interfaces /// /// Event args used for all related events. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public interface IScp1507Event : IPlayerEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs index fc62383340..d8a5537257 100644 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs @@ -12,7 +12,7 @@ namespace Exiled.Events.EventArgs.Interfaces /// /// Defines the base contract for all related events. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public interface IScp559Event : IExiledEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs deleted file mode 100644 index 8e491ee0b1..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs +++ /dev/null @@ -1,50 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Item -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.MarshmallowMan; - - /// - /// Contains all information before a marshmallow man punches. - /// - public class CacklingEventArgs : IMarshmallowEvent, IDeniableEvent - { - /// - /// Initializes a new instance of the class. - /// - /// The marshmallow item of the player cackling. - /// Whether the player is allowed to cackle. - public CacklingEventArgs(MarshmallowItem marshmallow, bool isAllowed = true) - { - Marshmallow = Item.Get(marshmallow); - Player = Marshmallow.Owner; - IsAllowed = isAllowed; - } - - /// - /// Gets the player cackling. - /// - public Player Player { get; } - - /// - public API.Features.Items.Item Item => Marshmallow; - - /// - /// Gets the marshmallow item of the player cackling. - /// - public Marshmallow Marshmallow { get; } - - /// - /// Gets or sets a value indicating whether the player is allowed to cackle. - /// - public bool IsAllowed { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs deleted file mode 100644 index d2d927d95a..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs +++ /dev/null @@ -1,50 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Item -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.MarshmallowMan; - - /// - /// Contains all information before a marshmallow man punches. - /// - public class PunchingEventArgs : IMarshmallowEvent, IDeniableEvent - { - /// - /// Initializes a new instance of the class. - /// - /// The marshmallow item of the player attacking. - /// Whether the player is allowed to punch. - public PunchingEventArgs(MarshmallowItem marshmallow, bool isAllowed = true) - { - Marshmallow = Item.Get(marshmallow); - Player = Marshmallow.Owner; - IsAllowed = isAllowed; - } - - /// - /// Gets the player punching. - /// - public Player Player { get; } - - /// - public Item Item => Marshmallow; - - /// - /// Gets the marshmallow item of the player punching. - /// - public Marshmallow Marshmallow { get; } - - /// - /// Gets or sets a value indicating whether the punch is allowed. - /// - public bool IsAllowed { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs index d8d38cc474..4c43eb1df8 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs @@ -7,13 +7,15 @@ namespace Exiled.Events.EventArgs.Map { - using System; - using API.Features; using API.Features.DamageHandlers; using API.Features.Roles; + using Interfaces; + using CustomAttackerHandler = API.Features.DamageHandlers.AttackerDamageHandler; + using DamageHandlerBase = PlayerStatsSystem.DamageHandlerBase; + /// /// Contains all information before C.A.S.S.I.E announces an SCP termination. /// @@ -25,14 +27,16 @@ public class AnnouncingScpTerminationEventArgs : IAttackerEvent, IDeniableEvent /// /// /// - /// - /// + /// + /// /// - public AnnouncingScpTerminationEventArgs(Player scp, string terminationCause) + public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHandlerBase) { Player = scp; Role = scp.Role; - TerminationCause = terminationCause; + DamageHandler = new CustomDamageHandler(scp, damageHandlerBase); + Attacker = DamageHandler.BaseIs(out CustomAttackerHandler customAttackerHandler) ? customAttackerHandler.Attacker : null; + TerminationCause = damageHandlerBase.CassieDeathAnnouncement.Announcement; IsAllowed = true; } @@ -54,13 +58,11 @@ public AnnouncingScpTerminationEventArgs(Player scp, string terminationCause) /// /// Gets the player who killed the SCP. /// - [Obsolete("Attacker can no longer be acquired for this event. This will be readded in a different event.")] public Player Attacker { get; } /// /// Gets or sets the . /// - [Obsolete("DamageHandler can no longer be acquired for this event. This will be readded in a different event.")] public CustomDamageHandler DamageHandler { get; set; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs index 038a3e16c4..168a0f578e 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs @@ -18,6 +18,8 @@ namespace Exiled.Events.EventArgs.Player /// public class ReceivingEffectEventArgs : IPlayerEvent, IDeniableEvent { + private byte intensity; + /// /// Initializes a new instance of the class. /// @@ -30,9 +32,9 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int { Player = player; Effect = effect; - Intensity = intensity; + this.intensity = intensity; CurrentIntensity = currentIntensity; - Duration = intensity is 0 ? 0 : duration; + Duration = duration; } /// @@ -51,9 +53,20 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int public float Duration { get; set; } = 0; /// - /// Gets or sets the value of the new intensity of the effect. + /// Gets or sets the value of the new intensity of the effect. Setting this to 0 is the same as setting IsAllowed to + /// . /// - public byte Intensity { get; set; } + public byte Intensity + { + get => intensity; + set + { + intensity = value; + + if (intensity == 0) + IsAllowed = false; + } + } /// /// Gets the value of the intensity of this effect on the player. diff --git a/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs deleted file mode 100644 index 6dce01109c..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs +++ /dev/null @@ -1,41 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Player -{ - using API.Features; - using API.Features.Items; - using Interfaces; - using InventorySystem.Items.Usables.Scp1576; - - /// - /// Contains all information after a SCP-1576 transmission has ended. - /// - public class Scp1576TransmissionEndedEventArgs : IPlayerEvent - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - public Scp1576TransmissionEndedEventArgs(Player player, Scp1576Item scp1576Item) - { - Player = player; - Scp1576 = Item.Get(scp1576Item); - } - - /// - /// Gets the that the transmission ended for. - /// - public Player Player { get; } - - /// - /// Gets the instance. - /// - public Exiled.API.Features.Items.Scp1576 Scp1576 { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs index c6aeed7ffb..e25e9fd728 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs @@ -28,14 +28,10 @@ public class UsedItemEventArgs : IPlayerEvent, IUsableEvent /// /// /// - /// - /// - /// - public UsedItemEventArgs(ReferenceHub player, UsableItem item, bool causedByHolstering) + public UsedItemEventArgs(ReferenceHub player, UsableItem item) { Player = Player.Get(player); - Usable = Item.Get(item) as Usable; - CausedByHolstering = causedByHolstering; + Usable = Item.Get(item) is Usable usable ? usable : null; } /// @@ -50,11 +46,5 @@ public UsedItemEventArgs(ReferenceHub player, UsableItem item, bool causedByHols /// Gets the player who used the item. /// public Player Player { get; } - - /// - /// Gets a value indicating whether this event was triggered by a player switching items (true) or by waiting after using the item (false). - /// - /// Use this value if you wish to keep the bug where you could switch items quickly to skip this event. - public bool CausedByHolstering { get; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs deleted file mode 100644 index 533ccbb5ce..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs +++ /dev/null @@ -1,51 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp127 -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Contains all information before SCP-127 gains experience. - /// - public class GainedExperienceEventArgs : IScp127Event - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - public GainedExperienceEventArgs(Scp127 scp127, float experience) - { - Scp127 = scp127; - Experience = experience; - Tier = Scp127.TierManagerModule.GetTierForExp(Experience + Scp127.Experience); - } - - /// - public Player Player => Scp127.Owner; - - /// - public Item Item => Scp127; - - /// - public Scp127 Scp127 { get; } - - /// - /// Gets the experience that SCP-127 has gained. - /// - public float Experience { get; } - - /// - /// Gets the tier. - /// - public Scp127Tier Tier { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs deleted file mode 100644 index 6a1d7b738b..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs +++ /dev/null @@ -1,59 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp127 -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Contains all information before SCP-127 gains experience. - /// - public class GainingExperienceEventArgs : IScp127Event, IDeniableEvent - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - public GainingExperienceEventArgs(Scp127 scp127, float experience, bool isAllowed = true) - { - Scp127 = scp127; - Experience = experience; - IsAllowed = isAllowed; - } - - /// - public Player Player => Scp127.Owner; - - /// - public Item Item => Scp127; - - /// - public Scp127 Scp127 { get; } - - /// - public bool IsAllowed { get; set; } - - /// - /// Gets or sets the gaining experience. - /// - public float Experience { get; set; } - - /// - /// Gets or sets the new tier. - /// - public Scp127Tier Tier - { - get => Scp127.TierManagerModule.GetTierForExp(Experience + Scp127.Experience); - set => Experience = Scp127.TierManagerModule.GetExpForTier(value) - Scp127.Experience; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs deleted file mode 100644 index 10810403d5..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs +++ /dev/null @@ -1,52 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp127 -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Contains all information after SCP-127 voice line is played. - /// - public class TalkedEventArgs : IScp127Event - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - public TalkedEventArgs(Scp127 scp127, Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority voiceLinePriority) - { - Scp127 = scp127; - VoiceLine = voiceLine; - Priority = voiceLinePriority; - } - - /// - public Player Player => Scp127.Owner; - - /// - public Item Item => Scp127; - - /// - public Scp127 Scp127 { get; } - - /// - /// Gets a voice line which is played. - /// - public Scp127VoiceLinesTranslation VoiceLine { get; } - - /// - /// Gets a priority for this play. - /// - public Scp127VoiceTriggerBase.VoiceLinePriority Priority { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs deleted file mode 100644 index b8934566a8..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs +++ /dev/null @@ -1,57 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp127 -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Contains all information before SCP-127 voice line is played. - /// - public class TalkingEventArgs : IScp127Event, IDeniableEvent - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - public TalkingEventArgs(Scp127 scp127, Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority voiceLinePriority, bool isAllowed = true) - { - Scp127 = scp127; - VoiceLine = voiceLine; - Priority = voiceLinePriority; - IsAllowed = isAllowed; - } - - /// - public Player Player => Scp127.Owner; - - /// - public Item Item => Scp127; - - /// - public Scp127 Scp127 { get; } - - /// - public bool IsAllowed { get; set; } - - /// - /// Gets or sets a voice line which is played. - /// - public Scp127VoiceLinesTranslation VoiceLine { get; set; } - - /// - /// Gets or sets a priority for this play. - /// - public Scp127VoiceTriggerBase.VoiceLinePriority Priority { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs index c6ea947e55..c58330e252 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs @@ -18,7 +18,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 attacks door. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class AttackingDoorEventArgs : IScp1507Event, IDeniableEvent, IDoorEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs index 7ab56f98e2..ae5ebb8450 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs @@ -16,7 +16,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 screams. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class ScreamingEventArgs : IScp1507Event, IDeniableEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs index 5cc50f9352..376eba5abf 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs @@ -19,7 +19,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before flamingos get spawned. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class SpawningFlamingosEventArgs : IDeniableEvent, IPlayerEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs index 10b713052e..0121d02d95 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 screams. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class UsingTapeEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs deleted file mode 100644 index d4935e6c92..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs +++ /dev/null @@ -1,40 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp2536 -{ - using Christmas.Scp2536; - using Exiled.API.Features; - using Exiled.Events.EventArgs.Interfaces; - - /// - /// Contains all information after SCP-2536 chooses target for spawning. - /// - public class FoundPositionEventArgs : IPlayerEvent - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - public FoundPositionEventArgs(Player player, Scp2536Spawnpoint spawnpoint) - { - Player = player; - Spawnpoint = spawnpoint; - } - - /// - /// Gets the player near whom SCP-2536 will spawn. - /// - public Player Player { get; } - - /// - /// Gets or sets the spawn point where SCP will spawn. - /// - public Scp2536Spawnpoint Spawnpoint { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs index 1a4a7408dc..b8b99f9ac9 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs @@ -15,7 +15,7 @@ namespace Exiled.Events.EventArgs.Scp559 /// /// Contains all information before a player interacts with SCP-559. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class InteractingScp559EventArgs : IScp559Event, IDeniableEvent, IPlayerEvent { /// @@ -23,11 +23,12 @@ public class InteractingScp559EventArgs : IScp559Event, IDeniableEvent, IPlayerE /// /// /// - public InteractingScp559EventArgs(Scp559 scp559, Player player) + /// + public InteractingScp559EventArgs(Scp559 scp559, Player player, bool isAllowed = true) { Player = player; Scp559 = scp559; - IsAllowed = scp559.RemainingSlices > 0 && PlayerRoles.PlayerRolesUtils.IsHuman(player.Role.Type); + IsAllowed = isAllowed; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs index c83baddd2c..6e3a81f06a 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs @@ -16,7 +16,7 @@ namespace Exiled.Events.EventArgs.Scp559 /// /// Contains all information before SCP-559 spawns. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class SpawningEventArgs : IDeniableEvent, IScp559Event { /// diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index adae6e21a8..a1bdd040a2 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -21,7 +21,6 @@ namespace Exiled.Events using PlayerRoles.FirstPersonControl.NetworkMessages; using PlayerRoles.Ragdolls; using PlayerRoles.RoleAssign; - using Respawning; using UnityEngine.SceneManagement; using UserSettings.ServerSpecific; @@ -74,7 +73,6 @@ public override void OnEnabled() Handlers.Scp049.ActivatingSense += Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified += Handlers.Internal.Round.OnVerified; Handlers.Map.ChangedIntoGrenade += Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; - Handlers.Warhead.Detonated += Handlers.Internal.Round.OnWarheadDetonated; RoleAssigner.OnPlayersSpawned += Handlers.Server.OnAllPlayersSpawned; CharacterClassManager.OnRoundStarted += Handlers.Server.OnRoundStarted; @@ -97,11 +95,6 @@ public override void OnEnabled() FpcServerPositionDistributor.RoleSyncEvent += Handlers.Internal.Round.OnRoleSyncEvent; - LabApi.Events.Handlers.Scp127Events.Talking += Handlers.Scp127.OnTalking; - LabApi.Events.Handlers.Scp127Events.Talked += Handlers.Scp127.OnTalked; - LabApi.Events.Handlers.Scp127Events.GainingExperience += Handlers.Scp127.OnGainingExperience; - LabApi.Events.Handlers.Scp127Events.GainExperience += Handlers.Scp127.OnGainedExperience; - ServerConsole.ReloadServerName(); } @@ -142,11 +135,6 @@ public override void OnDisabled() LabApi.Events.Handlers.PlayerEvents.UnloadingWeapon -= Handlers.Player.OnUnloadingWeapon; FpcServerPositionDistributor.RoleSyncEvent -= Handlers.Internal.Round.OnRoleSyncEvent; - - LabApi.Events.Handlers.Scp127Events.Talking -= Handlers.Scp127.OnTalking; - LabApi.Events.Handlers.Scp127Events.Talked -= Handlers.Scp127.OnTalked; - LabApi.Events.Handlers.Scp127Events.GainingExperience -= Handlers.Scp127.OnGainingExperience; - LabApi.Events.Handlers.Scp127Events.GainExperience -= Handlers.Scp127.OnGainedExperience; } /// diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index ff2833b79b..4cedb7a21e 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -29,7 +29,6 @@ namespace Exiled.Events.Handlers.Internal using InventorySystem.Items.Firearms.Attachments.Components; using InventorySystem.Items.Usables; using InventorySystem.Items.Usables.Scp244.Hypothermia; - using InventorySystem.Items.Usables.Scp330; using Mirror; using PlayerRoles; using PlayerRoles.FirstPersonControl; @@ -44,7 +43,7 @@ namespace Exiled.Events.Handlers.Internal internal static class Round { /// - public static void OnServerOnUsingCompleted(ReferenceHub hub, UsableItem usable) => Handlers.Player.OnUsedItem(new (hub, usable, false)); + public static void OnServerOnUsingCompleted(ReferenceHub hub, UsableItem usable) => Handlers.Player.OnUsedItem(new (hub, usable)); /// public static void OnWaitingForPlayers() @@ -109,9 +108,6 @@ public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { if (ev.Role.IsDead() || !ev.Role.IsFpcRole()) ev.IsAllowed = false; - - if (ev.DamageHandlerBase is Exiled.Events.Patches.Fixes.FixMarshmallowManFF fixMarshamllowManFf) - ev.DamageHandlerBase = fixMarshamllowManFf.MarshmallowItem.NewDamageHandler; } /// @@ -140,7 +136,7 @@ public static void OnVerified(VerifiedEventArgs ev) } // Fix bug that player that Join do not receive information about other players Scale - foreach (Player player in ReferenceHub.AllHubs.Select(Player.Get)) + foreach (Player player in Player.Enumerable) { player.SetFakeScale(player.Scale, new List() { ev.Player }); @@ -182,13 +178,6 @@ public static RoleTypeId OnRoleSyncEvent(ReferenceHub viewerHub, ReferenceHub ow return actualRole; } - /// - public static void OnWarheadDetonated() - { - // fix for black candy - CandyBlack.Outcomes.RemoveAll(outcome => outcome is TeleportOutcome); - } - private static void GenerateAttachments() { foreach (FirearmType firearmType in EnumUtils.Values) diff --git a/EXILED/Exiled.Events/Handlers/Item.cs b/EXILED/Exiled.Events/Handlers/Item.cs index b1ca257f09..9ac83aafd3 100644 --- a/EXILED/Exiled.Events/Handlers/Item.cs +++ b/EXILED/Exiled.Events/Handlers/Item.cs @@ -89,16 +89,6 @@ public static class Item /// public static Event JailbirdChangedWearState { get; set; } = new(); - /// - /// Invoked before a marshmallow man punches. - /// - public static Event Punching { get; set; } = new(); - - /// - /// Invoked before a marshmallow man cackles. - /// - public static Event Cackling { get; set; } = new(); - /// /// Called before the Jailbird's is changed. /// @@ -183,17 +173,5 @@ public static class Item /// /// The instance. public static void OnInspectedItem(InspectedItemEventArgs ev) => InspectedItem.InvokeSafely(ev); - - /// - /// Called before a marshmallow man punches. - /// - /// The instance. - public static void OnPunching(PunchingEventArgs ev) => Punching.InvokeSafely(ev); - - /// - /// Called before a marshmallow man cackles. - /// - /// The instance. - public static void OnCackling(CacklingEventArgs ev) => Cackling.InvokeSafely(ev); } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index 998b54f813..97e6137003 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -621,11 +621,6 @@ public class Player /// public static Event InteractingEmergencyButton { get; set; } = new(); - /// - /// Invoked after transmission has ended. - /// - public static Event Scp1576TransmissionEnded { get; set; } = new(); - /// /// Called before a player's emotion changed. /// @@ -1361,11 +1356,5 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item /// /// The instance. public static void OnInteractingEmergencyButton(InteractingEmergencyButtonEventArgs ev) => InteractingEmergencyButton.InvokeSafely(ev); - - /// - /// Called after a 1576 transmisiion has ended. - /// - /// The instance. - public static void OnScp1576TransmissionEnded(Scp1576TransmissionEndedEventArgs ev) => Scp1576TransmissionEnded.InvokeSafely(ev); } } diff --git a/EXILED/Exiled.Events/Handlers/Scp127.cs b/EXILED/Exiled.Events/Handlers/Scp127.cs deleted file mode 100644 index b3f86534d3..0000000000 --- a/EXILED/Exiled.Events/Handlers/Scp127.cs +++ /dev/null @@ -1,81 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Handlers -{ - using Exiled.Events.EventArgs.Scp127; - using Exiled.Events.Features; - using LabApi.Events.Arguments.Scp127Events; - -#pragma warning disable SA1623 - /// - /// SCP-127 event handlers. - /// - public static class Scp127 - { - /// - /// Invoked before SCP-127 voice line is played. - /// - public static Event Talking { get; set; } = new(); - - /// - /// Invoked after SCP-127 voice line is played. - /// - public static Event Talked { get; set; } = new(); - - /// - /// Invoked before SCP-127 gains experience. - /// - public static Event GainingExperience { get; set; } = new(); - - /// - /// Invoked after SCP-127 gains experience. - /// - public static Event GainedExperience { get; set; } = new(); - - /// - /// Called before SCP-127 voice line is played. - /// - /// The instance. - public static void OnTalking(Scp127TalkingEventArgs ev) - { - TalkingEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.VoiceLine, ev.Priority, ev.IsAllowed); - Talking.InvokeSafely(eventArgs); - - ev.Priority = eventArgs.Priority; - ev.VoiceLine = eventArgs.VoiceLine; - ev.IsAllowed = eventArgs.IsAllowed; - } - - /// - /// Called after SCP-127 voice line is played. - /// - /// The instance. - public static void OnTalked(Scp127TalkedEventArgs ev) - => Talked.InvokeSafely(new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.VoiceLine, ev.Priority)); - - /// - /// Called before SCP-127 gains experience. - /// - /// The instance. - public static void OnGainingExperience(Scp127GainingExperienceEventArgs ev) - { - GainingExperienceEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.ExperienceGain, ev.IsAllowed); - GainingExperience.InvokeSafely(eventArgs); - - ev.ExperienceGain = eventArgs.Experience; - ev.IsAllowed = eventArgs.IsAllowed; - } - - /// - /// Called after SCP-127 gains experience. - /// - /// The instance. - public static void OnGainedExperience(Scp127GainExperienceEventArgs ev) => - GainedExperience.InvokeSafely(new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.ExperienceGain)); - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Scp1507.cs b/EXILED/Exiled.Events/Handlers/Scp1507.cs index f36b16d633..63e4536d2c 100644 --- a/EXILED/Exiled.Events/Handlers/Scp1507.cs +++ b/EXILED/Exiled.Events/Handlers/Scp1507.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.Handlers /// /// SCP-1507 related events. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public static class Scp1507 { /// diff --git a/EXILED/Exiled.Events/Handlers/Scp2536.cs b/EXILED/Exiled.Events/Handlers/Scp2536.cs index 8c0d272583..3f7dfd1c58 100644 --- a/EXILED/Exiled.Events/Handlers/Scp2536.cs +++ b/EXILED/Exiled.Events/Handlers/Scp2536.cs @@ -21,11 +21,6 @@ public static class Scp2536 /// public static Event FindingPosition { get; set; } = new(); - /// - /// Invoked once SCP-2536 has found a spawn location. - /// - public static Event FoundPosition { get; set; } = new(); - /// /// Invoked before SCP-2536 gives a gift to a player. /// @@ -42,12 +37,6 @@ public static class Scp2536 /// The instance. public static void OnFindingPosition(FindingPositionEventArgs ev) => FindingPosition.InvokeSafely(ev); - /// - /// Called after SCP-2536 chooses a target. - /// - /// The instance. - public static void OnFoundPosition(FoundPositionEventArgs ev) => FoundPosition.InvokeSafely(ev); - /// /// Called before SCP-2536 gives a gift to a player. /// diff --git a/EXILED/Exiled.Events/Handlers/Scp559.cs b/EXILED/Exiled.Events/Handlers/Scp559.cs index 70d5387520..b17f520c9d 100644 --- a/EXILED/Exiled.Events/Handlers/Scp559.cs +++ b/EXILED/Exiled.Events/Handlers/Scp559.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.Handlers /// /// All SCP-559 related events. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public static class Scp559 { /// diff --git a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs index 1e7b55e3a8..0cb378ac02 100644 --- a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs +++ b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs @@ -8,61 +8,87 @@ namespace Exiled.Events.Patches.Events.Cassie { using System.Collections.Generic; - using System.Linq; using System.Reflection.Emit; using API.Features.Pools; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Cassie; - using global::Cassie; + using Handlers; + using HarmonyLib; using Respawning; using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Cassie), nameof(Cassie.SendingCassieMessage))] - [HarmonyPatch(typeof(CassieAnnouncementDispatcher), nameof(CassieAnnouncementDispatcher.PlayNewAnnouncement))] + [HarmonyPatch(typeof(RespawnEffectsController), nameof(RespawnEffectsController.PlayCassieAnnouncement))] internal static class SendingCassieMessage { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); - Label skipLabel = generator.DefineLabel(); Label returnLabel = generator.DefineLabel(); - newInstructions[0].WithLabels(skipLabel); - newInstructions.InsertRange( 0, new CodeInstruction[] { + // words new(OpCodes.Ldarg_0), - new(OpCodes.Isinst, typeof(CassieScpTerminationAnnouncement)), - new(OpCodes.Brtrue_S, skipLabel), - new(OpCodes.Ldarg_0), + // makeHold + new(OpCodes.Ldarg_1), + + // makeNoise + new(OpCodes.Ldarg_2), + + // customAnnouncement + new(OpCodes.Ldarg_3), + + // customSubtitles + new(OpCodes.Ldarg_S, 4), // isAllowed new(OpCodes.Ldc_I4_1), - // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(CassieAnnouncement, bool); - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs)).Single(ctor => ctor.GetParameters().Length == 2)), + // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(string, bool, bool, bool, string, bool); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Dup), new(OpCodes.Dup), new(OpCodes.Dup), // Cassie.OnSendingCassieMessage(ev); new(OpCodes.Call, Method(typeof(Cassie), nameof(Cassie.OnSendingCassieMessage))), - // annc = ev.Announcement - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Announcement))), + // words = ev.Words + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Words))), new(OpCodes.Starg_S, 0), + // makeHold = ev.MakeHold + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeHold))), + new(OpCodes.Starg_S, 1), + + // makeNoise = ev.MakeNoise + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeNoise))), + new(OpCodes.Starg_S, 2), + + // customAnnouncement = ev.IsCustomAnnouncement + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsCustomAnnouncement))), + new(OpCodes.Starg_S, 3), + + // customSubtitles = ev.CustomSubtitles + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.CustomSubtitles))), + new(OpCodes.Starg_S, 4), + // if (!IsAllowed) // return; new(OpCodes.Callvirt, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsAllowed))), diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs b/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs deleted file mode 100644 index fec7811ecf..0000000000 --- a/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs +++ /dev/null @@ -1,65 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Patches.Events.Item -{ - using System.Collections.Generic; - using System.Reflection.Emit; - - using Exiled.API.Features; - using Exiled.API.Features.Pools; - using Exiled.Events.Attributes; - using Exiled.Events.EventArgs.Item; - using HarmonyLib; - using InventorySystem.Items.MarshmallowMan; - - using static HarmonyLib.AccessTools; - - /// - /// Patch the . - /// Adds the event. - /// - [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Cackling))] - [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCackle))] - public class Cackling - { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - List newInstructions = ListPool.Pool.Get(instructions); - - Label retLabel = generator.DefineLabel(); - - int offset = 1; - int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; - - newInstructions.InsertRange(index, new[] - { - // this; - new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), - - // true - new(OpCodes.Ldc_I4_1), - - // ev = new CacklingEventArgs(MarshmallowItem, bool); - new(OpCodes.Newobj, Constructor(typeof(CacklingEventArgs), new[] { typeof(MarshmallowItem), typeof(bool) })), - new(OpCodes.Dup), - new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnCackling))), - - // if (!ev.IsAllowed) return - new(OpCodes.Callvirt, PropertyGetter(typeof(CacklingEventArgs), nameof(CacklingEventArgs.IsAllowed))), - new(OpCodes.Brfalse_S, retLabel), - }); - - newInstructions[newInstructions.Count - 1].WithLabels(retLabel); - - for (int z = 0; z < newInstructions.Count; z++) - yield return newInstructions[z]; - - ListPool.Pool.Return(newInstructions); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs b/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs deleted file mode 100644 index 15c74b57b1..0000000000 --- a/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs +++ /dev/null @@ -1,65 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Patches.Events.Item -{ - using System.Collections.Generic; - using System.Reflection.Emit; - - using Exiled.API.Features; - using Exiled.API.Features.Pools; - using Exiled.Events.Attributes; - using Exiled.Events.EventArgs.Item; - using HarmonyLib; - using InventorySystem.Items.MarshmallowMan; - - using static HarmonyLib.AccessTools; - - /// - /// Patch the . - /// Adds the event. - /// - [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Punching))] - [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCmd))] - public class Punching - { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - List newInstructions = ListPool.Pool.Get(instructions); - - Label retLabel = generator.DefineLabel(); - - int offset = 1; - int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; - - newInstructions[^1].WithLabels(retLabel); - - newInstructions.InsertRange(index, new[] - { - // this; - new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), - - // true - new(OpCodes.Ldc_I4_1), - - // ev = new PunchingEventArgs(MarshmallowItem, bool); - new(OpCodes.Newobj, Constructor(typeof(PunchingEventArgs), new[] { typeof(MarshmallowItem), typeof(bool) })), - new(OpCodes.Dup), - new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnPunching))), - - // if (!ev.IsAllowed) return - new(OpCodes.Callvirt, PropertyGetter(typeof(PunchingEventArgs), nameof(PunchingEventArgs.IsAllowed))), - new(OpCodes.Brfalse_S, retLabel), - }); - - for (int z = 0; z < newInstructions.Count; z++) - yield return newInstructions[z]; - - ListPool.Pool.Return(newInstructions); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs index 3033a0327d..0d53ebeefb 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs @@ -7,7 +7,6 @@ namespace Exiled.Events.Patches.Events.Map { - using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; @@ -18,12 +17,11 @@ namespace Exiled.Events.Patches.Events.Map using Exiled.Events.EventArgs.Map; using HarmonyLib; using Respawning.Announcements; - using Subtitles; using static HarmonyLib.AccessTools; /// - /// Patches and + /// Patches and /// to add event. /// [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] @@ -32,8 +30,8 @@ internal static class AnnouncingChaosEntrance { private static IEnumerable TargetMethods() { - yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncement)); - yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncement)); + yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncementString)); + yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncementString)); } private static IEnumerable Transpiler(IEnumerable instruction, ILGenerator generator) @@ -72,9 +70,6 @@ private static IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncement))] + [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncementString))] internal static class AnnouncingNtfEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -40,8 +39,8 @@ private static IEnumerable Transpiler(IEnumerable instruction.Calls(Method(typeof(UnitNamingRule), nameof(UnitNamingRule.TranslateToCassie)))) + offset; + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Stloc_3) + offset; newInstructions.InsertRange( index, @@ -51,10 +50,10 @@ private static IEnumerable Transpiler(IEnumerable]*?>"), new(OpCodes.Ldsfld, Field(typeof(string), nameof(string.Empty))), new(OpCodes.Call, Method(typeof(Regex), nameof(Regex.Replace), new System.Type[] { typeof(string), typeof(string), typeof(string) })), @@ -64,9 +63,9 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncement))] + [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncementString))] internal static class AnnouncingNtfMiniEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -35,17 +35,15 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Stloc_1) + 1; - newInstructions.InsertRange( - index, + 0, new CodeInstruction[] { // WaveAnnouncementBase new(OpCodes.Ldarg_0), // scpsLeft - new(OpCodes.Ldloc_1), + new(OpCodes.Ldloc_0), // null new(OpCodes.Ldnull), @@ -68,7 +66,7 @@ private static IEnumerable Transpiler(IEnumerable /// Patches - /// . + /// . /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingScpTermination))] - [HarmonyPatch(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.OnStartedPlaying))] + [HarmonyPatch(typeof(NineTailedFoxAnnouncer), nameof(NineTailedFoxAnnouncer.AnnounceScpTermination))] internal static class AnnouncingScpTermination { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); - LocalBuilder cause = generator.DeclareLocal(typeof(string)); - LocalBuilder enumerator = generator.DeclareLocal(typeof(IEnumerator)); - - ExceptionBlock beginTry = new(ExceptionBlockType.BeginExceptionBlock); - ExceptionBlock beginFinally = new(ExceptionBlockType.BeginFinallyBlock); - ExceptionBlock endFinally = new(ExceptionBlockType.EndExceptionBlock); + LocalBuilder ev = generator.DeclareLocal(typeof(AnnouncingScpTerminationEventArgs)); Label ret = generator.DefineLabel(); - Label entryLabel = generator.DefineLabel(); - Label loopLabel = generator.DefineLabel(); - Label leaveLabel = generator.DefineLabel(); - Label endFinallyLabel = generator.DefineLabel(); - - int offset = -1; - int index = newInstructions.FindIndex(i => i.LoadsField(Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts)))) + offset; - - newInstructions.RemoveRange(index, 2); - newInstructions.Insert(index, new CodeInstruction(OpCodes.Ldloc_S, cause)); - newInstructions[0].WithLabels(leaveLabel); + int offset = -4; + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Newobj && (ConstructorInfo)i.operand == GetDeclaredConstructors(typeof(LabApi.Events.Arguments.ServerEvents.CassieQueuingScpTerminationEventArgs))[0]) + offset; newInstructions.InsertRange( - 0, + index, new[] - { - new(OpCodes.Ldarg_0), - new(OpCodes.Ldfld, Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts))), - new(OpCodes.Stloc_S, cause), - new(OpCodes.Ldarg_0), - new(OpCodes.Callvirt, PropertyGetter(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.Victims))), - new(OpCodes.Callvirt, Method(typeof(IEnumerable), nameof(IEnumerable.GetEnumerator))), - new(OpCodes.Stloc_S, enumerator), - - // start of try - new CodeInstruction(OpCodes.Br_S, entryLabel).WithBlocks(beginTry), - - // start of loop - new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(loopLabel), - new(OpCodes.Callvirt, PropertyGetter(typeof(IEnumerator), nameof(IEnumerator.Current))), - new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(Footprint) })), - new(OpCodes.Ldloc_S, cause), - new(OpCodes.Newobj, Constructor(typeof(AnnouncingScpTerminationEventArgs), new[] { typeof(Player), typeof(string) })), - new(OpCodes.Dup), - new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), - new(OpCodes.Stloc_S, cause), - - // entry point - new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(entryLabel), - new(OpCodes.Callvirt, Method(typeof(IEnumerator), nameof(IEnumerator.MoveNext))), - new(OpCodes.Brtrue_S, loopLabel), - - // end of loop - new(OpCodes.Leave, leaveLabel), - - // begin finally - new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithBlocks(beginFinally), - new(OpCodes.Brfalse, endFinallyLabel), - new(OpCodes.Ldloc_S, enumerator), - new(OpCodes.Callvirt, Method(typeof(IDisposable), nameof(IDisposable.Dispose))), - - // end of finally - new CodeInstruction(OpCodes.Endfinally).WithLabels(endFinallyLabel).WithBlocks(endFinally), - }); + { + // Player.Get(scp) + new CodeInstruction(OpCodes.Ldarg_0), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), + + // hit + new(OpCodes.Ldarg_1), + + // AnnouncingScpTerminationEventArgs ev = new(Player, DamageHandlerBase) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(AnnouncingScpTerminationEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev.LocalIndex), + + // Map.OnAnnouncingScpTermination(ev) + new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), + + // if (!ev.IsAllowed) + // return; + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, ret), + + // hit = ev.DamageHandler.Base + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.DamageHandler))), + new(OpCodes.Callvirt, PropertyGetter(typeof(CustomDamageHandler), nameof(CustomDamageHandler.Base))), + new(OpCodes.Starg, 1), + + // announcement = ev.TerminationCause + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), + new(OpCodes.Stloc_0), + }); newInstructions[newInstructions.Count - 1].labels.Add(ret); diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs new file mode 100644 index 0000000000..7193f8d17f --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs @@ -0,0 +1,68 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Map +{ + using System.Collections.Generic; + using System.Reflection; + using System.Reflection.Emit; + using System.Text; + + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Map; + using HarmonyLib; + using Respawning.Announcements; + + using static HarmonyLib.AccessTools; + + /// + /// Patches to prevent cassie from playing empty string. + /// + [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingNtfEntrance))] + [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] + [HarmonyPatch(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.PlayAnnouncement))] + internal static class AnnouncingTeamEntrance + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label returnLabel = generator.DefineLabel(); + + // the instruction that sends subtitles is called before stringReturn is created (and thus checked) so we need to move it so that empty (or disallowed) message's subtitles are not sent. + // this removes the Ldarg_0 and the CallVirt + int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.SendSubtitles)))); + CodeInstruction sendSubtitlesInstruction = newInstructions[index]; + newInstructions.RemoveRange(index - 2, 3); + + index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldsfld); + + newInstructions.InsertRange(index, new[] + { + // if (stringReturn == "") + // return; + new(OpCodes.Ldloc_S, 4), + new(OpCodes.Ldstr, string.Empty), + new(OpCodes.Ceq), + new(OpCodes.Brtrue_S, returnLabel), + + // send subtitles before cassie message, but after our check. + new(OpCodes.Ldarg_0), + new(OpCodes.Ldarg_1), + sendSubtitlesInstruction, + }); + + newInstructions[newInstructions.Count - 1].labels.Add(returnLabel); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs index 4af8bd4e11..b379bdec1a 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs @@ -89,13 +89,14 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(RoomConnectorSpawnpointBase), nameof(RoomConnectorSpawnpointBase.SetupAllRoomConnectors)))); - List GateAArmory, - - /// - /// Represents the door in . - /// - HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/EffectType.cs b/EXILED/Exiled.API/Enums/EffectType.cs index 9bed0519c9..e70e273e77 100644 --- a/EXILED/Exiled.API/Enums/EffectType.cs +++ b/EXILED/Exiled.API/Enums/EffectType.cs @@ -216,7 +216,7 @@ public enum EffectType /// /// Makes you a marshmallow guy. /// - // [Obsolete("Not functional in-game")] + [Obsolete("Not functional in-game")] Marshmallow, /// @@ -261,27 +261,27 @@ public enum EffectType Blurred, /// - /// Makes you a flamingo . + /// Makes you a flamingo. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] BecomingFlamingo, /// - /// Makes you a Child after eating Cake . + /// Makes you a Child after eating Cake. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] Scp559, /// - /// Scp956 found you . + /// Scp956 found you. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] Scp956Target, /// - /// you are snowed . + /// you are snowed. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] Snowed, /// @@ -317,93 +317,78 @@ public enum EffectType /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] Metal, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] OrangeCandy, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] OrangeWitness, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] Prismatic, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] SlowMetabolism, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] Spicy, /// /// . /// - // [Obsolete("Only availaible for Halloween or Christmas.")] + // [Obsolete("Only availaible for Halloween.")] SugarCrave, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] SugarHigh, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] SugarRush, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] TemporaryBypass, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] TraumatizedByEvil, /// /// . /// - [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween.")] WhiteCandy, /// /// . /// Scp1509Resurrected, - - /// - /// . - /// - FocusedVision, - - /// - /// . - /// - AnomalousRegeneration, - - /// - /// . - /// - AnomalousTarget, } } diff --git a/EXILED/Exiled.API/Enums/GlassType.cs b/EXILED/Exiled.API/Enums/GlassType.cs index fef4d59f44..85c068108f 100644 --- a/EXILED/Exiled.API/Enums/GlassType.cs +++ b/EXILED/Exiled.API/Enums/GlassType.cs @@ -84,10 +84,5 @@ public enum GlassType /// Represents the window in . /// GateAArmory, - - /// - /// Represents the window in - /// - HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/PrefabType.cs b/EXILED/Exiled.API/Enums/PrefabType.cs index 43936f1d80..6a52ce7995 100644 --- a/EXILED/Exiled.API/Enums/PrefabType.cs +++ b/EXILED/Exiled.API/Enums/PrefabType.cs @@ -417,47 +417,5 @@ public enum PrefabType [Prefab(213466224, "SCP-939 Ragdoll Halloween")] Scp939RagdollHalloween, - - [Prefab(689741320, "SCP-559 Cake")] - Scp559Cake, - - [Prefab(2657863153, "SCP-956")] - Scp956, - - [Prefab(1205960739, "SCP-2536 Tree")] - Scp2536, - - [Prefab(2102014206, "Snowpile")] - Snowpile, - - [Prefab(3401975113, "Scp018Projectile Christmas")] - Scp018ProjectileChristmas, - - [Prefab(3223468476, "SnowballProjectile")] - SnowballProjectile, - - [Prefab(296717882, "CoalPickup")] - CoalPickup, - - [Prefab(409273101, "TapePlayerPickup")] - Scp1507TapePickup, - - [Prefab(3971391978, "Scp021JPickup")] - Scp021JPickup, - - [Prefab(142820664, "CoalProjectile")] - CoalProjectile, - - [Prefab(2405470903, "Scp2536Projectile")] - Scp2536Projectile, - - [Prefab(1496232901, "SCP-173 Ragdoll Variant")] - Scp173RagdollChristmas, - - [Prefab(6069361, "SnowPoop - TantrumObj")] - SnowTantrum, - - [Prefab(3654754970, "SCP-1507 Ragdoll")] - Scp1507Ragdoll, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/ProjectileType.cs b/EXILED/Exiled.API/Enums/ProjectileType.cs index 2d95210924..a8072ed48e 100644 --- a/EXILED/Exiled.API/Enums/ProjectileType.cs +++ b/EXILED/Exiled.API/Enums/ProjectileType.cs @@ -51,21 +51,21 @@ public enum ProjectileType /// Coal. /// Used by . /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] Coal, /// /// SpecialCoal. /// Used by . /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] SpecialCoal, /// /// Snowball. /// Used by . /// - // [Obsolete("Only availaible for Christmas.")] + [Obsolete("Only availaible for Christmas.")] Snowball, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/RoomType.cs b/EXILED/Exiled.API/Enums/RoomType.cs index 6dceeea6e2..0b7737c193 100644 --- a/EXILED/Exiled.API/Enums/RoomType.cs +++ b/EXILED/Exiled.API/Enums/RoomType.cs @@ -353,10 +353,5 @@ public enum RoomType /// Heavy Containment Zone's straight hall room with lava. /// HczDss12 = HczIncineratorWayside, - - /// - /// Heavy Containment Zone's T-intersection with a ramp in it. - /// - HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/Side.cs b/EXILED/Exiled.API/Enums/Side.cs index 5accace2f3..5e9c063be7 100644 --- a/EXILED/Exiled.API/Enums/Side.cs +++ b/EXILED/Exiled.API/Enums/Side.cs @@ -52,10 +52,5 @@ public enum Side /// No team. Same as . /// None, - - /// - /// Contains and . Same as . - /// - Flamingos, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Exiled.API.csproj b/EXILED/Exiled.API/Exiled.API.csproj index 70f81bf0d1..31fe36e002 100644 --- a/EXILED/Exiled.API/Exiled.API.csproj +++ b/EXILED/Exiled.API/Exiled.API.csproj @@ -34,7 +34,6 @@ - diff --git a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs index 6fde63477d..95dfc33727 100644 --- a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs +++ b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs @@ -204,13 +204,6 @@ public static DamageType GetDamageType(DamageHandlerBase damageHandlerBase) Log.Warn($"{nameof(DamageTypeExtensions)}.{nameof(damageHandlerBase)}: No matching {nameof(DamageType)} for {nameof(UniversalDamageHandler)} with ID {translation.Id}, type will be reported as {DamageType.Unknown}. Report this to EXILED Devs."); return DamageType.Unknown; } - - case AttackerDamageHandler attackerDamageHandler: - { - if (Player.TryGet(attackerDamageHandler.Attacker, out Player attacker) && attacker.CurrentItem?.Type == ItemType.MarshmallowItem) - return DamageType.Marshmallow; - return DamageType.Unknown; - } } return DamageType.Unknown; diff --git a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs index 088438e085..c44a32362d 100644 --- a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs +++ b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs @@ -101,9 +101,6 @@ public static class EffectTypeExtension { EffectType.TraumatizedByEvil, typeof(TraumatizedByEvil) }, { EffectType.WhiteCandy, typeof(WhiteCandy) }, { EffectType.Scp1509Resurrected, typeof(Scp1509Resurrected) }, - { EffectType.FocusedVision, typeof(FocusedVision) }, - { EffectType.AnomalousRegeneration, typeof(AnomalousRegeneration) }, - { EffectType.AnomalousTarget, typeof(AnomalousTarget) }, #pragma warning restore CS0618 }); diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs index 3ba47fd9a8..605e6466c0 100644 --- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs +++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs @@ -17,7 +17,6 @@ namespace Exiled.API.Extensions using AdminToys; using AudioPooling; - using Cassie; using CustomPlayerEffects; using Exiled.API.Enums; using Exiled.API.Features.Items; @@ -513,12 +512,13 @@ public static void ResyncKeycardPickup(CustomKeycardPickup customKeycard) /// Same on 's isSubtitles. public static void PlayCassieAnnouncement(this Player player, string words, bool makeHold = false, bool makeNoise = true, bool isSubtitles = false) { - CassieAnnouncement announcement = new(new CassieTtsPayload(words, isSubtitles, makeHold), 0, makeNoise ? 1 : 0); - - // processes makeNoise - announcement.OnStartedPlaying(); - - announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); + foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) + { + if (controller != null) + { + SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), words, makeHold, makeNoise, isSubtitles); + } + } } /// @@ -533,12 +533,23 @@ public static void PlayCassieAnnouncement(this Player player, string words, bool /// Same on 's isSubtitles. public static void MessageTranslated(this Player player, string words, string translation, string customSubtitles, bool makeHold = false, bool makeNoise = true, bool isSubtitles = true) { - CassieAnnouncement announcement = new(new CassieTtsPayload(words, customSubtitles, makeHold), 0, makeNoise ? 1 : 0); + StringBuilder announcement = StringBuilderPool.Pool.Get(); - // processes makeNoise - announcement.OnStartedPlaying(); + string[] cassies = words.Split('\n'); + string[] translations = translation.Split('\n'); - announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); + for (int i = 0; i < cassies.Length; i++) + announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); + + string message = StringBuilderPool.Pool.ToStringReturn(announcement); + + foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) + { + if (controller != null) + { + SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), message, makeHold, makeNoise, isSubtitles, customSubtitles); + } + } } /// diff --git a/EXILED/Exiled.API/Extensions/RoleExtensions.cs b/EXILED/Exiled.API/Extensions/RoleExtensions.cs index db1a7c99a9..369910654a 100644 --- a/EXILED/Exiled.API/Extensions/RoleExtensions.cs +++ b/EXILED/Exiled.API/Extensions/RoleExtensions.cs @@ -70,7 +70,6 @@ public static class RoleExtensions Team.FoundationForces or Team.Scientists => Side.Mtf, Team.ChaosInsurgency or Team.ClassD => Side.ChaosInsurgency, Team.OtherAlive => Side.Tutorial, - Team.Flamingos => Side.Flamingos, _ => Side.None, }; @@ -81,13 +80,12 @@ public static class RoleExtensions /// . public static Team GetTeam(this RoleTypeId roleType) => roleType switch { - RoleTypeId.ChaosConscript or RoleTypeId.ChaosMarauder or RoleTypeId.ChaosRepressor or RoleTypeId.ChaosRifleman or RoleTypeId.ChaosFlamingo => Team.ChaosInsurgency, + RoleTypeId.ChaosConscript or RoleTypeId.ChaosMarauder or RoleTypeId.ChaosRepressor or RoleTypeId.ChaosRifleman => Team.ChaosInsurgency, RoleTypeId.Scientist => Team.Scientists, RoleTypeId.ClassD => Team.ClassD, - RoleTypeId.Scp049 or RoleTypeId.Scp939 or RoleTypeId.Scp0492 or RoleTypeId.Scp079 or RoleTypeId.Scp096 or RoleTypeId.Scp106 or RoleTypeId.Scp173 or RoleTypeId.Scp3114 or RoleTypeId.ZombieFlamingo=> Team.SCPs, - RoleTypeId.FacilityGuard or RoleTypeId.NtfCaptain or RoleTypeId.NtfPrivate or RoleTypeId.NtfSergeant or RoleTypeId.NtfSpecialist or RoleTypeId.NtfFlamingo => Team.FoundationForces, + RoleTypeId.Scp049 or RoleTypeId.Scp939 or RoleTypeId.Scp0492 or RoleTypeId.Scp079 or RoleTypeId.Scp096 or RoleTypeId.Scp106 or RoleTypeId.Scp173 or RoleTypeId.Scp3114 => Team.SCPs, + RoleTypeId.FacilityGuard or RoleTypeId.NtfCaptain or RoleTypeId.NtfPrivate or RoleTypeId.NtfSergeant or RoleTypeId.NtfSpecialist => Team.FoundationForces, RoleTypeId.Tutorial => Team.OtherAlive, - RoleTypeId.Flamingo or RoleTypeId.AlphaFlamingo => Team.Flamingos, _ => Team.Dead, }; @@ -133,7 +131,6 @@ public static bool TryGetRoleBase(this RoleTypeId roleType, out T roleBase) Team.ClassD or Team.ChaosInsurgency => LeadingTeam.ChaosInsurgency, Team.FoundationForces or Team.Scientists => LeadingTeam.FacilityForces, Team.SCPs => LeadingTeam.Anomalies, - Team.Flamingos => LeadingTeam.Flamingo, _ => LeadingTeam.Draw, }; diff --git a/EXILED/Exiled.API/Features/Camera.cs b/EXILED/Exiled.API/Features/Camera.cs index fa17a77540..fca5cbbc73 100644 --- a/EXILED/Exiled.API/Features/Camera.cs +++ b/EXILED/Exiled.API/Features/Camera.cs @@ -143,11 +143,6 @@ public class Camera : IWrapper, IWorldSpace ["GATE A ELEVATORS"] = CameraType.EzGateAElevators, ["GATE B INTERIOR"] = CameraType.EzGateBInterior, ["GATE B SIDE"] = CameraType.EzGateBSide, - ["GATE A STAIRWELL"] = CameraType.EzGateAStairwell, - ["GATE A UPPER"] = CameraType.EzGateAUpper, - ["LOADING BAY"] = CameraType.HczLoadingBay, - ["HCZ LOADING RAMP"] = CameraType.HczLoadingBayRamp, - ["STAIRWELL"] = CameraType.HczLoadingBayStairwell, // CustomCamera ["EZ ARM CAMERA TOY"] = CameraType.EzArmCameraToy, diff --git a/EXILED/Exiled.API/Features/Cassie.cs b/EXILED/Exiled.API/Features/Cassie.cs index 475e68ad4e..0730f9a5a9 100644 --- a/EXILED/Exiled.API/Features/Cassie.cs +++ b/EXILED/Exiled.API/Features/Cassie.cs @@ -7,19 +7,19 @@ namespace Exiled.API.Features { - using System; using System.Collections.Generic; using System.Linq; using System.Text; using Exiled.API.Features.Pools; - using global::Cassie; - using global::Cassie.Interpreters; + using MEC; + using PlayerRoles; + using PlayerStatsSystem; + using Respawning; - using Respawning.NamingRules; using CustomFirearmHandler = DamageHandlers.FirearmDamageHandler; using CustomHandlerBase = DamageHandlers.DamageHandlerBase; @@ -29,15 +29,20 @@ namespace Exiled.API.Features /// public static class Cassie { + /// + /// Gets the singleton. + /// + public static NineTailedFoxAnnouncer Announcer => NineTailedFoxAnnouncer.singleton; + /// /// Gets a value indicating whether C.A.S.S.I.E is currently announcing. Does not include decontamination or Alpha Warhead Messages. /// - public static bool IsSpeaking => CassieAnnouncementDispatcher.AllAnnouncements.Count != 0; + public static bool IsSpeaking => Announcer.queue.Count != 0; /// - /// Gets a of objects that C.A.S.S.I.E recognizes. + /// Gets a of objects that C.A.S.S.I.E recognizes. /// - public static IReadOnlyCollection VoiceLines => CassieAnnouncementDispatcher.AllAnnouncements; + public static IReadOnlyCollection VoiceLines => Announcer.voiceLines; /// /// Reproduce a non-glitched C.A.S.S.I.E message. @@ -47,7 +52,7 @@ public static class Cassie /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void Message(string message, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); + RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles); /// /// Reproduce a non-glitched C.A.S.S.I.E message with a possibility to custom the subtitles. @@ -59,7 +64,14 @@ public static void Message(string message, bool isHeld = false, bool isNoisy = t /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void MessageTranslated(string message, string translation, bool isHeld = false, bool isNoisy = true, bool isSubtitles = true) { - new CassieAnnouncement(new CassieTtsPayload(message, translation, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); + StringBuilder announcement = StringBuilderPool.Pool.Get(); + string[] cassies = message.Split('\n'); + string[] translations = translation.Split('\n'); + for (int i = 0; i < cassies.Length; i++) + announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); + + RespawnEffectsController.PlayCassieAnnouncement(announcement.ToString(), isHeld, isNoisy, isSubtitles); + StringBuilderPool.Pool.Return(announcement); } /// @@ -69,7 +81,7 @@ public static void MessageTranslated(string message, string translation, bool is /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void GlitchyMessage(string message, float glitchChance, float jamChance) => - new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue(); + Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance); /// /// Reproduce a non-glitched C.A.S.S.I.E message after a certain amount of seconds. @@ -80,7 +92,7 @@ public static void GlitchyMessage(string message, float glitchChance, float jamC /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void DelayedMessage(string message, float delay, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue()); + Timing.CallDelayed(delay, () => RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles)); /// /// Reproduce a glitchy C.A.S.S.I.E announcement after a certain period of seconds. @@ -90,53 +102,17 @@ public static void DelayedMessage(string message, float delay, bool isHeld = fal /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void DelayedGlitchyMessage(string message, float delay, float glitchChance, float jamChance) => - Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue()); - - /// - /// Calculates the duration of a C.A.S.S.I.E message. - /// - /// The message, which duration will be calculated. - /// An obsolete parameter. - /// Another obsolete parameter. - /// Duration (in seconds) of specified message. - [Obsolete("Please use CalculateDuration(string)", true)] - public static float CalculateDuration(string message, bool obsolete1, float obsolete2) => CalculateDuration(message); + Timing.CallDelayed(delay, () => Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance)); /// /// Calculates the duration of a C.A.S.S.I.E message. /// /// The message, which duration will be calculated. + /// Determines if a number won't be converted to its full pronunciation. + /// The speed of the message. /// Duration (in seconds) of specified message. - public static float CalculateDuration(string message) - { - if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) - { - return 0; - } - - float value = 0; - string[] lines = message.Split(' ', StringSplitOptions.RemoveEmptyEntries); - - CassiePlaybackModifiers modifiers = new(); - StringBuilder builder = StringBuilderPool.Pool.Get(); - - for (int i = 0; i < lines.Length; i++) - { - foreach (CassieInterpreter interpreter in CassieTtsAnnouncer.Interpreters) - { - bool halt; - foreach (CassieInterpreter.Result result in interpreter.GetResults(cassieLineDatabase, ref modifiers, lines[i], builder, out halt)) - { - value += (float)result.Modifiers.GetTimeUntilNextWord(result.Line); - } - - if (halt) - break; - } - } - - return value; - } + public static float CalculateDuration(string message, bool rawNumber = false, float speed = 1f) + => Announcer.CalculateDuration(message, rawNumber, speed); /// /// Converts a into a Cassie-Readable CONTAINMENTUNIT. @@ -144,16 +120,8 @@ public static float CalculateDuration(string message) /// . /// Unit Name. /// Containment Unit text. - public static string ConvertTeam(Team team, string unitName) => team switch - { - Team.FoundationForces when NamingRulesManager.TryGetNamingRule(team, out UnitNamingRule unitNamingRule) => "CONTAINMENTUNIT " + unitNamingRule.TranslateToCassie(unitName), - Team.FoundationForces => "CONTAINMENTUNIT UNKNOWN", - Team.ChaosInsurgency => "BY CHAOSINSURGENCY", - Team.Scientists => "BY SCIENCE PERSONNEL", - Team.ClassD => "BY CLASSD PERSONNEL", - Team.Flamingos => "BY SCP 1 5 0 7", - _ => "UNKNOWN", - }; + public static string ConvertTeam(Team team, string unitName) + => NineTailedFoxAnnouncer.ConvertTeam(team, unitName); /// /// Converts a number into a Cassie-Readable String. @@ -161,23 +129,7 @@ Team.FoundationForces when NamingRulesManager.TryGetNamingRule(team, out UnitNam /// Number to convert. /// A CASSIE-readable representing the number. public static string ConvertNumber(int num) - { - if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) - { - return string.Empty; - } - - NumberInterpreter numberInterpreter = (NumberInterpreter)CassieTtsAnnouncer.Interpreters.FirstOrDefault((CassieInterpreter x) => x is NumberInterpreter); - if (numberInterpreter == null) - { - return string.Empty; - } - - CassiePlaybackModifiers cassiePlaybackModifiers = default; - StringBuilder stringBuilder = new(); - numberInterpreter.GetResults(cassieLineDatabase, ref cassiePlaybackModifiers, num.ToString(), stringBuilder, out bool flag); - return stringBuilder.ToString(); - } + => NineTailedFoxAnnouncer.ConvertNumber(num); /// /// Announce a SCP Termination. @@ -185,7 +137,7 @@ public static string ConvertNumber(int num) /// SCP to announce termination of. /// HitInformation. public static void ScpTermination(Player scp, DamageHandlerBase info) - => CassieScpTerminationAnnouncement.AnnounceScpTermination(scp.ReferenceHub, info); + => NineTailedFoxAnnouncer.AnnounceScpTermination(scp.ReferenceHub, info); /// /// Announces the termination of a custom SCP name. @@ -215,14 +167,14 @@ public static void CustomScpTermination(string scpName, CustomHandlerBase info) /// /// Clears the C.A.S.S.I.E queue. /// - public static void Clear() => CassieAnnouncementDispatcher.ClearAll(); + public static void Clear() => RespawnEffectsController.ClearQueue(); /// /// Gets a value indicating whether the given word is a valid C.A.S.S.I.E word. /// /// The word to check. /// if the word is valid; otherwise, . - public static bool IsValid(string word) => CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase) ? cassieLineDatabase.AllLines.Any(line => line.ApiName.ToUpper() == word.ToUpper()) : false; + public static bool IsValid(string word) => Announcer.voiceLines.Any(line => line.apiName.ToUpper() == word.ToUpper()); /// /// Gets a value indicating whether the given sentence is all valid C.A.S.S.I.E word. diff --git a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs index fde6e9e00a..67b464474f 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs @@ -39,17 +39,11 @@ public CustomDamageHandler(Player target, BaseHandler baseHandler) if (Attacker is not null) { if (baseHandler is BaseScpDamageHandler) - { CustomBase = new ScpDamageHandler(target, baseHandler); - } + else if (Attacker.CurrentItem is not null && Attacker.CurrentItem.Type.IsWeapon() && baseHandler is BaseFirearmHandler) + CustomBase = new FirearmDamageHandler(Attacker.CurrentItem, target, baseHandler); else - { - Item item = Attacker.CurrentItem; - if (item is not null && item.Type.IsWeapon() && baseHandler is BaseFirearmHandler) - CustomBase = new FirearmDamageHandler(item, target, baseHandler); - else - CustomBase = new DamageHandler(target, Attacker); - } + CustomBase = new DamageHandler(target, Attacker); } else { diff --git a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs index 248e89452b..ec59d5ee5a 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs @@ -271,13 +271,6 @@ protected DamageType GetDamageType(BaseHandler damageHandler = null) FirearmType.FRMG0 => DamageType.Frmg0, _ => DamageType.Firearm }; - - case PlayerStatsSystem.AttackerDamageHandler attackerDamageHandler: - { - if (Player.TryGet(attackerDamageHandler.Attacker, out Player attacker) && attacker.CurrentItem?.Type == ItemType.MarshmallowItem) - return DamageType.Marshmallow; - return DamageType.Unknown; - } } return DamageType.Unknown; diff --git a/EXILED/Exiled.API/Features/Doors/Door.cs b/EXILED/Exiled.API/Features/Doors/Door.cs index a8163f207c..19718900a7 100644 --- a/EXILED/Exiled.API/Features/Doors/Door.cs +++ b/EXILED/Exiled.API/Features/Doors/Door.cs @@ -624,7 +624,6 @@ private DoorType GetDoorType() RoomType.HczEzCheckpointA => DoorType.CheckpointArmoryA, RoomType.HczEzCheckpointB => DoorType.CheckpointArmoryB, RoomType.EzGateA => DoorType.GateAArmory, - RoomType.HczLoadingBay => DoorType.HczLoadingBay, _ => DoorType.UnknownDoor, }, "Unsecured Pryable GateDoor" => Room?.Type switch diff --git a/EXILED/Exiled.API/Features/Effect.cs b/EXILED/Exiled.API/Features/Effect.cs index 426b68dcdc..f901966917 100644 --- a/EXILED/Exiled.API/Features/Effect.cs +++ b/EXILED/Exiled.API/Features/Effect.cs @@ -35,7 +35,7 @@ public Effect(StatusEffectBase statusEffectBase) if (!statusEffectBase.TryGetEffectType(out EffectType effect)) Log.Error($"EffectType not found please report to Exiled BugReport : {statusEffectBase}"); Type = effect; - Duration = statusEffectBase.TimeLeft; + Duration = statusEffectBase.Duration; Intensity = statusEffectBase.Intensity; IsEnabled = statusEffectBase.IsEnabled; } diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs index 8fb2688bb7..50a2538c64 100644 --- a/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs @@ -11,8 +11,9 @@ namespace Exiled.API.Features.Items.FirearmModules using Exiled.API.Features.Items.FirearmModules.Barrel; using Exiled.API.Features.Items.FirearmModules.Primary; + using InventorySystem.Items.Firearms.Modules; - using InventorySystem.Items.Firearms.Modules.Scp127; + using UnityEngine; /// @@ -65,12 +66,8 @@ public static Magazine Get(IAmmoContainerModule module) PumpActionModule pump => new PumpBarrelMagazine(pump), IPrimaryAmmoContainerModule primary => primary switch { + MagazineModule magazine => new NormalMagazine(magazine), CylinderAmmoModule cylinder => new CylinderMagazine(cylinder), - MagazineModule magazine => magazine switch - { - Scp127MagazineModule scp127MagazineModule => new Scp127Magazine(scp127MagazineModule), - _ => new NormalMagazine(magazine) - }, _ => null, }, _ => null, diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs deleted file mode 100644 index c3226169ea..0000000000 --- a/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs +++ /dev/null @@ -1,80 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.API.Features.Items.FirearmModules.Primary -{ - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Represents a normal magazine for SCP-127. - /// - public class Scp127Magazine : NormalMagazine - { - /// - /// Initializes a new instance of the class. - /// - /// - public Scp127Magazine(Scp127MagazineModule magazine) - : base(magazine) - { - MagazineModule = magazine; - } - - /// - public new Scp127MagazineModule MagazineModule { get; } - - /// - /// Gets or sets the kill bonus. - /// - public int KillBonus - { - get => MagazineModule.KillBonus; - set => MagazineModule.KillBonus = value; - } - - /// - /// Gets or sets the rank up bonus. - /// - public int RankUpBonus - { - get => MagazineModule.RankUpBonus; - set => MagazineModule.RankUpBonus = value; - } - - /// - /// Gets or sets all settings. - /// - public Scp127MagazineModule.RegenerationSettings[] RegenerationPerTier - { - get => MagazineModule._regenerationPerTier; - set => MagazineModule._regenerationPerTier = value; - } - - /// - /// Gets the current setting. - /// - public Scp127MagazineModule.RegenerationSettings ActiveSetting => MagazineModule.ActiveSettings; - - /// - /// Gets or sets a pause in bullets regeneration process. - /// - public float RemainingRegenPause - { - get => MagazineModule._remainingRegenPause; - set => MagazineModule._remainingRegenPause = value; - } - - /// - /// Gets or sets the amount of bullets that should be regenerated. - /// - public float RegenProgress - { - get => MagazineModule._regenProgress; - set => MagazineModule._regenProgress = value; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs index 89bb189c42..f9d8a74a0d 100644 --- a/EXILED/Exiled.API/Features/Items/Item.cs +++ b/EXILED/Exiled.API/Features/Items/Item.cs @@ -22,7 +22,6 @@ namespace Exiled.API.Features.Items using InventorySystem.Items.Firearms.Ammo; using InventorySystem.Items.Jailbird; using InventorySystem.Items.Keycards; - using InventorySystem.Items.MarshmallowMan; using InventorySystem.Items.MicroHID; using InventorySystem.Items.Pickups; using InventorySystem.Items.Radio; @@ -219,11 +218,7 @@ public static Item Get(ItemBase itemBase) return itemBase switch { - InventorySystem.Items.Firearms.Firearm firearm => firearm.ItemTypeId switch - { - ItemType.GunSCP127 => new Scp127(firearm), - _ => new Firearm(firearm), - }, + InventorySystem.Items.Firearms.Firearm firearm => new Firearm(firearm), KeycardItem keycard => keycard switch { ChaosKeycardItem chaosKeycardItem => new ChaosKeycard(chaosKeycardItem), @@ -261,7 +256,6 @@ public static Item Get(ItemBase itemBase) _ => new Throwable(throwable), }, Scp1509Item scp1509 => new Scp1509(scp1509), - MarshmallowItem marshmallow => new Marshmallow(marshmallow), _ => new(itemBase), }; } @@ -324,11 +318,7 @@ public static T Get(ushort serial) /// The created. This can be cast as a subclass. public static Item Create(ItemType type, Player owner = null) => type.GetTemplate() switch { - InventorySystem.Items.Firearms.Firearm => type switch - { - ItemType.GunSCP127 => new Scp127(), - _ => new Firearm(type), - }, + InventorySystem.Items.Firearms.Firearm => new Firearm(type), KeycardItem keycard => keycard switch { ChaosKeycardItem => new ChaosKeycard(type), @@ -366,7 +356,6 @@ public static T Get(ushort serial) _ => new Throwable(type, owner), }, Scp1509Item => new Scp1509(), - MarshmallowItem => new Marshmallow(type, owner), _ => new(type), }; diff --git a/EXILED/Exiled.API/Features/Items/Jailbird.cs b/EXILED/Exiled.API/Features/Items/Jailbird.cs index 4cc9a59c86..b68a3473c2 100644 --- a/EXILED/Exiled.API/Features/Items/Jailbird.cs +++ b/EXILED/Exiled.API/Features/Items/Jailbird.cs @@ -52,8 +52,8 @@ internal Jailbird() /// public float MeleeDamage { - get => Base.MeleeDamage; - set => Base.MeleeDamage = value; + get => Base._hitreg._damageMelee; + set => Base._hitreg._damageMelee = value; } /// @@ -61,8 +61,8 @@ public float MeleeDamage /// public float ChargeDamage { - get => Base._chargeDamage; - set => Base._chargeDamage = value; + get => Base._hitreg._damageCharge; + set => Base._hitreg._damageCharge = value; } /// @@ -70,8 +70,8 @@ public float ChargeDamage /// public float FlashDuration { - get => Base._flashedDuration; - set => Base._flashedDuration = value; + get => Base._hitreg._flashedDuration; + set => Base._hitreg._flashedDuration = value; } /// @@ -79,17 +79,17 @@ public float FlashDuration /// public float ConcussionDuration { - get => Base._concussionDuration; - set => Base._concussionDuration = value; + get => Base._hitreg._concussionDuration; + set => Base._hitreg._concussionDuration = value; } /// - /// Gets or sets the radius of the Jailbird's hit radius. + /// Gets or sets the radius of the Jailbird's hit register. /// public float Radius { - get => Base._hitregRadius; - set => Base._hitregRadius = value; + get => Base._hitreg._hitregRadius; + set => Base._hitreg._hitregRadius = value; } /// @@ -97,10 +97,10 @@ public float Radius /// public float TotalDamageDealt { - get => Base.TotalMeleeDamageDealt; + get => Base._hitreg.TotalMeleeDamageDealt; set { - Base.TotalMeleeDamageDealt = value; + Base._hitreg.TotalMeleeDamageDealt = value; Base._deterioration.RecheckUsage(); } } diff --git a/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs b/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs index bab50d19ce..8d8bdad39d 100644 --- a/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs +++ b/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs @@ -43,8 +43,7 @@ internal ChaosKeycard(ItemType type) /// /// Gets the this encapsulates. /// - /// Can be null, but shouldn't be during usage. - public SnakeEngine SnakeEngine => ChaosKeycardItem.SnakeSessions.TryGetValue(Serial, out SnakeEngine engine) ? engine : null; + public SnakeEngine SnakeEngine => Base._localEngine; /// /// Returns the Keycard in a human readable format. diff --git a/EXILED/Exiled.API/Features/Items/Marshmallow.cs b/EXILED/Exiled.API/Features/Items/Marshmallow.cs deleted file mode 100644 index 349fe342fb..0000000000 --- a/EXILED/Exiled.API/Features/Items/Marshmallow.cs +++ /dev/null @@ -1,102 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.API.Features.Items -{ - using CustomPlayerEffects; - using Exiled.API.Interfaces; - using InventorySystem.Items.MarshmallowMan; - using PlayerStatsSystem; - using UnityEngine; - - /// - /// A wrapper class for . - /// - public class Marshmallow : Item, IWrapper - { - /// - /// Initializes a new instance of the class. - /// - /// The base class. - public Marshmallow(MarshmallowItem itemBase) - : base(itemBase) - { - Base = itemBase; - } - - /// - /// Initializes a new instance of the class. - /// - /// The of the marshmallow item. - /// The owner of the marshmallow item. Leave for no owner. - internal Marshmallow(ItemType type, Player owner = null) - : base((MarshmallowItem)(owner ?? Server.Host).Inventory.CreateItemInstance(new(type, 0), false)) - { - } - - /// - /// Gets the that this class is encapsulating. - /// - public new MarshmallowItem Base { get; } - - /// - /// Gets a value indicating whether this marshmallow man is evil. - /// - /// See in regards to making a marshmallow evil. - public bool Evil => Base.EvilMode; - - /// - /// Gets or sets the of the marshmallow man that would be used if he was evil. - /// - public AhpStat.AhpProcess EvilAhpProcess - { - get => Base.EvilAHPProcess; - set - { - if (Evil && value is null) - return; - - Base.EvilAHPProcess = value; - } - } - - /// - /// Cackles for the owner even if they are not evil. - /// - /// How long until the player can cackle again (negative values do not affect current cooldown). - /// How long players near the marshmallow man get effected by . - public void Cackle(double cooldown = -1, float duration = 5) - { - if (cooldown >= 0) - Base._cackleCooldown.Trigger(cooldown); - - Base.ServerSendPublicRpc(writer => - { - writer.WriteByte(4); - Base._cackleCooldown.WriteCooldown(writer); - }); - - foreach (Player player in Player.List) - { - if (Vector3.Distance(player.Position, Owner.Position) <= 5F && player.CurrentItem is not Marshmallow { Evil: true }) - player.EnableEffect(duration); - } - } - - /// - /// Makes the owner of this marshmallow evil. You CANNOT undo this without resetting the player. - /// - /// The of the new evil player. - public void MakeEvil(AhpStat.AhpProcess evilProcess = null) - { - if (Evil) - return; - - Base.ReleaseEvil(evilProcess ?? EvilAhpProcess ?? Owner.GetModule().ServerAddProcess(450F, 450F, 0F, 1F, 0F, true)); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Items/Scp127.cs b/EXILED/Exiled.API/Features/Items/Scp127.cs deleted file mode 100644 index 2c71fbe4bb..0000000000 --- a/EXILED/Exiled.API/Features/Items/Scp127.cs +++ /dev/null @@ -1,274 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.API.Features.Items -{ - using System.Collections.Generic; - using System.Linq; - - using InventorySystem.Items.Firearms.Modules; - using InventorySystem.Items.Firearms.Modules.Scp127; - using UnityEngine; - - /// - /// Represents SCP-127. - /// - public class Scp127 : Firearm - { - #pragma warning disable SA1401 - /// - /// Custom amount of max HS. - /// - internal float? CustomHsMax; - #pragma warning restore SA1401 - - /// - /// Initializes a new instance of the class. - /// - /// - public Scp127(InventorySystem.Items.Firearms.Firearm itemBase) - : base(itemBase) - { - foreach (ModuleBase module in Base.Modules) - { - switch (module) - { - case Scp127HumeModule humeModule: - HumeModule = humeModule; - break; - case Scp127TierManagerModule tierManagerModule: - TierManagerModule = tierManagerModule; - break; - case Scp127VoiceLineManagerModule voiceLineManagerModule: - VoiceLineManagerModule = voiceLineManagerModule; - break; - } - } - } - - /// - /// Initializes a new instance of the class. - /// - internal Scp127() - : this((InventorySystem.Items.Firearms.Firearm)Server.Host.Inventory.CreateItemInstance(new(ItemType.GunSCP127, 0), false)) - { - } - - /// - /// Gets a collection of all active HS sessions. - /// - public static List ActiveHumeShieldSessions => Scp127HumeModule.ServerActiveSessions; - - /// - /// Gets the instance. - /// - public Scp127HumeModule HumeModule { get; } - - /// - /// Gets the instance. - /// - public Scp127TierManagerModule TierManagerModule { get; } - - /// - /// Gets the instance. - /// - public Scp127VoiceLineManagerModule VoiceLineManagerModule { get; } - - /// - /// Gets or sets the maximum amount of HS. - /// - /// If setter is used, after tier chance this value won't be edited automatically. - public float HsMax - { - get => CustomHsMax ?? HumeModule.HsMax; - set => CustomHsMax = value; - } - - /// - /// Gets or sets a shield regeneration rate. - /// - public float ShieldRegenRate - { - get => HumeModule.ShieldRegenRate; - set => HumeModule.ShieldRegenRate = value; - } - - /// - /// Gets or sets a shield decay time. - /// - public float ShieldDecayRate - { - get => HumeModule.ShieldDecayRate; - set => HumeModule.ShieldDecayRate = value; - } - - /// - /// Gets or sets a pause before HS starts regeneration after damage being taken. - /// - public float ShieldOnDamagePause - { - get => HumeModule.ShieldOnDamagePause; - set => HumeModule.ShieldOnDamagePause = value; - } - - /// - /// Gets or sets a delay before HS starts dropping after unequipment. - /// - public float UnequipDecayDelay - { - get => HumeModule.UnequipDecayDelay; - set => HumeModule.UnequipDecayDelay = value; - } - - /// - /// Gets or sets a HumeShield regeneration. - /// - public float HsRegeneration - { - get => HumeModule.HsRegeneration; - set => HumeModule.HsRegeneration = value; - } - - /// - /// Gets or sets an experience bonus for kill. - /// - public float KillBonus - { - get => TierManagerModule.KillBonus; - set => TierManagerModule.KillBonus = value; - } - - /// - /// Gets or sets an amount of passive experience increase. - /// - public float PassiveExpAmount - { - get => TierManagerModule.PassiveExpAmount; - set => TierManagerModule.PassiveExpAmount = value; - } - - /// - /// Gets or sets an interval of passive experience increase. - /// - public float PassiveExpInterval - { - get => TierManagerModule.PassiveExpInterval; - set => TierManagerModule.PassiveExpInterval = value; - } - - /// - /// Gets or sets a collection of all tier thresholds. - /// - public Scp127TierManagerModule.TierThreshold[] TierThresholds - { - get => TierManagerModule.Thresholds; - set => TierManagerModule.Thresholds = value; - } - - /// - /// Gets or sets current tier. - /// - public Scp127Tier CurrentTier - { - get => TierManagerModule.CurTier; - set => TierManagerModule.CurTier = value; - } - - /// - /// Gets or sets the current experience amount. - /// - public float Experience - { - get => TierManagerModule.ServerExp; - set => TierManagerModule.ServerExp = value; - } - - /// - /// Gets the instance record. - /// - public Scp127TierManagerModule.InstanceRecord InstanceRecord => Scp127TierManagerModule.GetRecord(Serial); - - /// - /// Gets the Owner stats. - /// - public Scp127TierManagerModule.OwnerStats OwnerStats => Scp127TierManagerModule.GetStats(Base); - - /// - /// Gets or sets all Voice Triggers. - /// - public Scp127VoiceTriggerBase[] VoiceTriggers - { - get => VoiceLineManagerModule._foundTriggers; - set => VoiceLineManagerModule._foundTriggers = value; - } - - /// - /// Gets a collection of players that are friends with this SCP-127. - /// - public IEnumerable Friends - { - get - { - if (!Scp127VoiceLineManagerModule.FriendshipMemory.TryGetValue(Serial, out HashSet uintSet)) - return null; - - return uintSet.Select(Player.Get); - } - } - - /// - /// Increases experience. - /// - /// Amount to add. - public void IncreaseExperience(float amount) => TierManagerModule.ServerIncreaseExp(Base, amount); - - /// - /// Sets owner stats. - /// - /// New experience amount. - public void SetOwnerStats(float exp) => TierManagerModule.ServerSetStats(exp); - - /// - /// Sends tier stats. - /// - /// New tier. - /// New progress. - public void SendTierStats(Scp127Tier tier, byte progress) => TierManagerModule.ServerSendStats(Serial, Owner.ReferenceHub, tier, progress); - - /// - /// Tries to play voice line. - /// - /// Voice line to play. - /// Priority of the play. - /// true if voice line has been played successfully. Otherwise, false. - public bool TryPlayVoiceLine(Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority priority = Scp127VoiceTriggerBase.VoiceLinePriority.Normal) - { - if (!VoiceLineManagerModule.TryFindVoiceLine(voiceLine, out Scp127VoiceTriggerBase triggerBase, out AudioClip audioClip)) - return false; - - VoiceLineManagerModule.ServerSendVoiceLine(triggerBase, null, audioClip, (byte)priority); - return true; - } - - /// - /// Checks if this instance of SCP-127 and have friendship. - /// - /// Target to check. - /// true if this instance of SCP-127 and have friendship. Otherwise, false. - public bool HasFriendship(Player player) => Scp127VoiceLineManagerModule.HasFriendship(Serial, player.ReferenceHub); - - /// - /// Adds player as a friend. - /// - /// Target to be added. - public void AddFriend(Player player) - { - HashSet uints = Scp127VoiceLineManagerModule.FriendshipMemory.GetOrAddNew(Serial); - uints.Add(player.NetId); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Lift.cs b/EXILED/Exiled.API/Features/Lift.cs index d191cd6764..469a33bd22 100644 --- a/EXILED/Exiled.API/Features/Lift.cs +++ b/EXILED/Exiled.API/Features/Lift.cs @@ -47,7 +47,6 @@ public class Lift : IWrapper, IWorldSpace internal Lift(ElevatorChamber elevator) { Base = elevator; - ElevatorAutoReturn = elevator.GetComponent(); ElevatorChamberToLift.Add(elevator, this); internalDoorsList.AddRange(Elevator.AllElevatorDoors[Group]); @@ -74,12 +73,6 @@ internal Lift(ElevatorChamber elevator) /// public ElevatorChamber Base { get; } - /// - /// Gets the base . - /// - /// Would be null for any elevator that do not used . - public ElevatorAutoReturn ElevatorAutoReturn { get; } - /// /// Gets a value of the internal doors list. /// diff --git a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs index eaaf77cb7a..0494d2e966 100644 --- a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs @@ -123,11 +123,11 @@ protected override void InitializeProperties(ItemBase itemBase) base.InitializeProperties(itemBase); if (itemBase is JailbirdItem jailbirdItem) { - MeleeDamage = jailbirdItem.MeleeDamage; - ChargeDamage = jailbirdItem._chargeDamage; - FlashDuration = jailbirdItem._flashedDuration; - ConcussionDuration = jailbirdItem._concussionDuration; - Radius = Radius; + MeleeDamage = jailbirdItem._hitreg._damageMelee; + ChargeDamage = jailbirdItem._hitreg._damageCharge; + FlashDuration = jailbirdItem._hitreg._flashedDuration; + ConcussionDuration = jailbirdItem._hitreg._concussionDuration; + Radius = jailbirdItem._hitreg._hitregRadius; } } } diff --git a/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs b/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs index 935bc636ca..b11c1cb0e9 100644 --- a/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs @@ -15,7 +15,7 @@ namespace Exiled.API.Features.Pickups using BaseScp1509 = InventorySystem.Items.Scp1509.Scp1509Pickup; /// - /// A wrapper class for a Scp1509 pickup. + /// A wrapper class for a Radio pickup. /// public class Scp1509Pickup : Pickup, IWrapper { diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 956fcf7f23..a61d640a84 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -648,7 +648,7 @@ public ScpSpawnPreferences.SpawnPreferences ScpPreferences /// /// Gets a value indicating whether the player is reloading a weapon. /// - public bool IsReloading => CurrentItem is Firearm firearm && firearm.IsReloading; + public bool IsReloading => CurrentItem is Firearm firearm && !firearm.IsReloading; /// /// Gets a value indicating whether the player is aiming with a weapon. @@ -1982,24 +1982,10 @@ public void SetRank(string name, UserGroup group) ReferenceHub.serverRoles.SetGroup(group, false, false); } - ServerStatic.PermissionsHandler.Members[UserId] = name; - } - - /// - /// If the rank(group) exists in the remote admin config, it will assign it to the player. - /// - /// The rank name to be set. - /// if the rank(group) was found and successfully assigned, otherwise. - public bool TrySetRank(string name) - { - if (ServerStatic.PermissionsHandler.Groups.TryGetValue(name, out UserGroup userGroup)) - { - ReferenceHub.serverRoles.SetGroup(userGroup, false, false); + if (ServerStatic.PermissionsHandler.Members.ContainsKey(UserId)) ServerStatic.PermissionsHandler.Members[UserId] = name; - return true; - } - - return false; + else + ServerStatic.PermissionsHandler.Members.Add(UserId, name); } /// @@ -2043,21 +2029,6 @@ public void Broadcast(Broadcast broadcast, bool shouldClearPrevious = false) Broadcast(broadcast.Duration, broadcast.Content, broadcast.Type, shouldClearPrevious); } - /// - /// Send an to the player. - /// - /// The to be broadcasted. - /// if Cassie failed to play it or it's play nothing, otherwise it's return the duration of the annoucement. - public float CassieAnnouncement(global::Cassie.CassieAnnouncement cassieAnnouncement) - { - global::Cassie.CassieAnnouncementDispatcher.CurrentAnnouncement.OnStartedPlaying(); - global::Cassie.CassieTtsPayload payload = cassieAnnouncement.Payload; - if (!global::Cassie.CassieTtsAnnouncer.TryPlay(payload, out float totalduration)) - return 0; - payload.SendToHubsConditionally(x => x == ReferenceHub); - return totalduration; - } - /// /// Drops an item from the player's inventory. /// @@ -2090,12 +2061,10 @@ public void DropItem(Item item, bool isThrown = false) /// Dropped item's . public Pickup DropHeldItem() { - Item item = CurrentItem; - - if (item is null) + if (CurrentItem is null) return null; - return DropItem(item); + return DropItem(CurrentItem); } /// @@ -3480,7 +3449,10 @@ public void SyncEffect(Effect effect) { if (effect.IsEnabled) { - EnableEffect(effect.Type, effect.Intensity, effect.Duration, effect.AddDurationIfActive); + EnableEffect(effect.Type, effect.Duration, effect.AddDurationIfActive); + + if (effect.Intensity > 0) + ChangeEffectIntensity(effect.Type, effect.Intensity, effect.Duration); } } @@ -3608,7 +3580,8 @@ public void ChangeEffectIntensity(byte intensity, float duration = 0) { if (ReferenceHub.playerEffectsController.TryGetEffect(out T statusEffect)) { - statusEffect.ServerSetState(intensity, duration, false); + statusEffect.Intensity = intensity; + statusEffect.ServerChangeDuration(duration, true); } } @@ -3622,7 +3595,8 @@ public void ChangeEffectIntensity(EffectType type, byte intensity, float duratio { if (TryGetEffect(type, out StatusEffectBase statusEffect)) { - statusEffect.ServerSetState(intensity, duration, false); + statusEffect.Intensity = intensity; + statusEffect.ServerChangeDuration(duration, false); } } diff --git a/EXILED/Exiled.API/Features/Recontainer.cs b/EXILED/Exiled.API/Features/Recontainer.cs index dbc31a35bf..17f59c97d5 100644 --- a/EXILED/Exiled.API/Features/Recontainer.cs +++ b/EXILED/Exiled.API/Features/Recontainer.cs @@ -7,7 +7,6 @@ namespace Exiled.API.Features { - using System; using System.Collections.Generic; using System.Linq; @@ -34,8 +33,7 @@ public static class Recontainer /// /// Gets a value indicating whether the C.A.S.S.I.E is currently busy. /// - [Obsolete("Use Cassie.IsSpeaking instead")] - public static bool IsCassieBusy => Cassie.IsSpeaking; + public static bool IsCassieBusy => Base.CassieBusy; /// /// Gets a value about how many generator have been activated. @@ -63,8 +61,11 @@ public static bool IsContainmentZoneLocked /// /// Gets or sets the delay to wait before overcharging. /// - [Obsolete("Will be removed in Exiled 10, patch the Cassie079RecontainAnnouncement ctor if you need this functionality")] - public static float OverchargeDelay { get; set; } + public static float OverchargeDelay + { + get => Base._activationDelay; + set => Base._activationDelay = value; + } /// /// Gets or sets the lockdown duration. @@ -187,7 +188,7 @@ public static bool IsContainmentSequenceSuccessful /// /// The announcement to play. /// The glitchy multiplier. - public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, false, false, null); + public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, glitchyMultiplier); /// /// Begins the overcharge procedure. @@ -198,6 +199,7 @@ public static void BeginOvercharge(bool endOvercharge = true) Base.BeginOvercharge(); if (endOvercharge) { + Base._delayStopwatch.Stop(); Base._unlockStopwatch.Start(); } } @@ -226,7 +228,7 @@ public static void BeginOvercharge(bool endOvercharge = true) /// /// Begins the recontainment procedure. /// - public static void Recontain() => Base.Recontain(false); + public static void Recontain() => Base.Recontain(); /// /// Refreshes the activator. diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs index 9a1156833e..2b0d75cf00 100644 --- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs +++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs @@ -300,30 +300,6 @@ public BasicRagdoll Ragdoll /// public SpectatableModuleBase SpectatableModuleBase => FirstPersonController.SpectatorModule; - /// - /// Tries to get the of a specified bone. - /// - /// The bone to get the of. - /// - /// When this method returns, contains the of the specified bone, if found; - /// otherwise, null. - /// - /// true if the bone transform was found; otherwise, false. - public bool TryGetBoneTransform(HumanBodyBones bone, out Transform boneTransform) - { - boneTransform = null; - - if (Model is not AnimatedCharacterModel animatedModel) - return false; - - Animator animator = animatedModel.Animator; - if (animator == null || animator.avatar == null || !animator.avatar.isValid || !animator.avatar.isHuman) - return false; - - boneTransform = animator.GetBoneTransform(bone); - return boneTransform != null; - } - /// /// Resets the 's stamina. /// diff --git a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs index 6283226eb4..1c015e2ff0 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs @@ -271,7 +271,8 @@ public void Attack(Player player) else { cardiacArrest.SetAttacker(AttackAbility.Owner); - cardiacArrest.ServerSetState(1, AttackAbility._statusEffectDuration, false); + cardiacArrest.Intensity = 1; + cardiacArrest.ServerChangeDuration(AttackAbility._statusEffectDuration, false); } SenseAbility.OnServerHit(AttackAbility._target); diff --git a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs index 6e78b6c662..a59e699ac9 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs @@ -16,8 +16,6 @@ namespace Exiled.API.Features.Roles using PlayerRoles.PlayableScps.Scp096; using PlayerRoles.Subroutines; - using UnityEngine; - using Scp096GameRole = PlayerRoles.PlayableScps.Scp096.Scp096Role; /// @@ -141,20 +139,6 @@ internal Scp096Role(Scp096GameRole baseRole) /// public bool AttackPossible => AttackAbility.AttackPossible; - /// - /// Gets the head transform of SCP-096's character model. - /// - public Transform HeadTransform - { - get - { - if (Model is not Scp096CharacterModel scp96AnimatedCharacterModel) - return null; - - return scp96AnimatedCharacterModel.Head; - } - } - /// /// Gets or sets the Charge Ability Cooldown. /// @@ -322,4 +306,4 @@ public void Charge(float cooldown = 1f) /// The Spawn Chance. public float GetSpawnChance(List alreadySpawned) => Base.GetSpawnChance(alreadySpawned); } -} +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs b/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs index 170bda116a..a4c9ba78cf 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs @@ -20,7 +20,7 @@ namespace Exiled.API.Features.Roles /// /// Defines a role that represents SCP-1507. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class Scp1507Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp { /// diff --git a/EXILED/Exiled.API/Features/Room.cs b/EXILED/Exiled.API/Features/Room.cs index 846a76509c..a81a24173f 100644 --- a/EXILED/Exiled.API/Features/Room.cs +++ b/EXILED/Exiled.API/Features/Room.cs @@ -506,7 +506,6 @@ private static RoomType FindType(GameObject gameObject) "HCZ_ChkpB" => RoomType.HczElevatorB, "HCZ_127" => RoomType.Hcz127, "HCZ_ServerRoom" => RoomType.HczServerRoom, - "HCZ_Intersection_Ramp" => RoomType.HczLoadingBay, "EZ_GateA" => RoomType.EzGateA, "EZ_GateB" => RoomType.EzGateB, "EZ_ThreeWay" => RoomType.EzTCross, diff --git a/EXILED/Exiled.API/Features/Scp559.cs b/EXILED/Exiled.API/Features/Scp559.cs index d05702b351..08fc899047 100644 --- a/EXILED/Exiled.API/Features/Scp559.cs +++ b/EXILED/Exiled.API/Features/Scp559.cs @@ -18,7 +18,7 @@ namespace Exiled.API.Features /// /// Represents a cake. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class Scp559 : IWrapper, IPosition { /// @@ -50,34 +50,20 @@ public Scp559(Scp559Cake cakeBase) /// /// Gets a with spawnpoint in rooms. /// - public static Dictionary SpawnPositions { get; } = Scp559Spawnpoint.InstancesPerRoom.ToDictionary(kvp => kvp.Key.Name, kvp => - { - Transform roomTransform = kvp.Key.transform; - Transform spawnTransform = kvp.Value.transform; - - Vector3 localPos = roomTransform.InverseTransformPoint(spawnTransform.position); - - return new Vector4(localPos.x, localPos.y, localPos.z, spawnTransform.eulerAngles.y); - }); + public static Dictionary SpawnPositions => Scp559Cake.Spawnpoints; /// /// Gets the list of all available spawnpoints. /// - public static List AvailableSpawnpoints => Scp559Cake.PossibleSpawnpoints.Select(spawnpoint => - { - Transform t = spawnpoint.transform; - return new Vector4(t.position.x, t.position.y, t.position.z, t.eulerAngles.y); - }).ToList(); + public static List AvailableSpawnpoints => Scp559Cake.PossiblePositions; /// /// Gets or sets offset for spawning near pedestals. /// public static Vector3 PedestalOffset { - get => new(0, -Scp559Spawnpoint.PedestalHeight, 0); - - [Obsolete("Setter no longer works")] - set { } + get => Scp559Cake.PedestalOffset; + set => Scp559Cake.PedestalOffset.Set(value.x, value.y, value.z); } /// diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs index 825cfb3566..96b8311fdf 100644 --- a/EXILED/Exiled.API/Features/Server.cs +++ b/EXILED/Exiled.API/Features/Server.cs @@ -111,27 +111,7 @@ public static string Name /// /// Gets the actual ticks per second of the server. /// - public static double Tps - { - get - { - double delta = Time.deltaTime; - - if (delta <= 0) - return MaxTps; - - double tps = 1d / delta; - - tps = Math.Min(tps, MaxTps); - - return tps; - } - } - - /// - /// Gets the average ticks per second of the server. - /// - public static double SmoothTps => Math.Round(1f / Time.smoothDeltaTime); + public static double Tps => Math.Round(1f / Time.smoothDeltaTime); /// /// Gets or sets the max ticks per second of the server. diff --git a/EXILED/Exiled.API/Features/Waves/TimedWave.cs b/EXILED/Exiled.API/Features/Waves/TimedWave.cs index 6e9a5c55bf..8856727c58 100644 --- a/EXILED/Exiled.API/Features/Waves/TimedWave.cs +++ b/EXILED/Exiled.API/Features/Waves/TimedWave.cs @@ -193,13 +193,13 @@ public static List GetTimedWaves() /// Plays the announcement for this wave. /// /// Wave must implement . - public void PlayAnnouncement() => Announcement?.PlayAnnouncement([], Base as IAnnouncedWave); + public void PlayAnnouncement() => Announcement?.PlayAnnouncement(new()); /// /// Plays the announcement for this wave. /// /// Wave must implement . /// The list of Player to spawn. - public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList(), Base as IAnnouncedWave); + public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList()); } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Window.cs b/EXILED/Exiled.API/Features/Window.cs index 2d327ff0c4..e5a1624e0d 100644 --- a/EXILED/Exiled.API/Features/Window.cs +++ b/EXILED/Exiled.API/Features/Window.cs @@ -231,7 +231,6 @@ public void DamageWindow(float amount, DamageHandlerBase handler) RoomType.HczEzCheckpointB => GlassType.HczEzCheckpointB, RoomType.EzGateA when Base.name[7] == '5' => GlassType.GateAArmory, RoomType.EzGateA => GlassType.GateAPit, - RoomType.HczLoadingBay => GlassType.HczLoadingBay, _ => GlassType.Unknown, }, "Window" => Room?.Type switch diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs index 182f47155e..fa39569e0a 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs @@ -1013,6 +1013,15 @@ private void OnInternalOwnerHandcuffing(HandcuffingEventArgs ev) continue; OnOwnerHandcuffing(new OwnerHandcuffingEventArgs(item, ev)); + + if (!ev.IsAllowed) + continue; + + ev.Target.RemoveItem(item); + + TrackedSerials.Remove(item.Serial); + + Spawn(ev.Target, item, ev.Target); } } diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index afce01ccdf..f29e2d525c 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -790,12 +790,6 @@ public bool TryAddFriendlyFire(Dictionary ffRules, bool overw return true; } - /// - /// Returns the CustomRole in a human-readable format. - /// - /// A string containing CustomRole-related data. - public override string ToString() => $"{Name} ({Id})"; - /// /// Tries to register this role. /// diff --git a/EXILED/Exiled.CustomRoles/Commands/Get.cs b/EXILED/Exiled.CustomRoles/Commands/Get.cs deleted file mode 100644 index 7d96d5f6b4..0000000000 --- a/EXILED/Exiled.CustomRoles/Commands/Get.cs +++ /dev/null @@ -1,123 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.CustomRoles.Commands -{ - using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Linq; - using System.Text; - - using CommandSystem; - using Exiled.API.Extensions; - using Exiled.API.Features; - using Exiled.API.Features.Pools; - using Exiled.CustomRoles.API; - using Exiled.CustomRoles.API.Features; - using Exiled.Permissions.Extensions; - using HarmonyLib; - - /// - /// The command to get specified player(s) current custom roles. - /// - internal sealed class Get : ICommand - { - private Get() - { - } - - /// - /// Gets the command instance. - /// - public static Get Instance { get; } = new(); - - /// - public string Command => "get"; - - /// - public string[] Aliases { get; } = Array.Empty(); - - /// - public string Description => "Gets the specified player(s)' current custom role(s)."; - - /// - public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) - { - if (!sender.CheckPermission("customroles.get")) - { - response = "Permission Denied, required: customroles.get"; - return false; - } - - List players = ListPool.Pool.Get(); - - if (arguments.Count > 0) - { - string identifier = string.Join(" ", arguments); - - switch (identifier.ToLower()) - { - case "*": - case "all": - players.AddRange(Player.List); - break; - default: - players.AddRange(Player.GetProcessedData(arguments)); - break; - } - - if (players.IsEmpty()) - { - if (arguments.Count > 0 || !Player.TryGet(sender, out Player player)) - { - response = $"Player not found: {identifier}"; - return false; - } - - players.Add(player); - } - } - else - { - response = "get "; - return false; - } - - StringBuilder builder = StringBuilderPool.Pool.Get(); - - builder.AppendLine(); - builder.AppendLine("====================== Custom Roles ======================"); - - foreach (Player target in players) - { - ReadOnlyCollection roles = target.GetCustomRoles(); - builder.Append((target.DisplayNickname + (target.HasCustomName ? $" ({target.Nickname})" : string.Empty)).PadRight(30 + (target.HasCustomName ? 23 : 0))); - builder.Append(" "); - builder.Append($"({target.Id})".PadRight(5)); - if (roles.IsEmpty()) - { - builder.AppendLine(" | No Custom Role"); - } - else - { - // builder.Append($" | [{string.Join(", ", roles.Select(role => $"{role}"))}]"); - builder.Append(" | ["); - builder.Append(string.Join(", ", roles.Select(role => $"{role}"))); - builder.AppendLine("]"); - } - } - - builder.AppendLine("=========================================================="); - - ListPool.Pool.Return(players); - - response = StringBuilderPool.Pool.ToStringReturn(builder); - return true; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.CustomRoles/Commands/Give.cs b/EXILED/Exiled.CustomRoles/Commands/Give.cs index 9666bff990..2f74b46498 100644 --- a/EXILED/Exiled.CustomRoles/Commands/Give.cs +++ b/EXILED/Exiled.CustomRoles/Commands/Give.cs @@ -83,7 +83,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s string identifier = string.Join(" ", arguments.Skip(1)); - switch (identifier.ToLower()) + switch (identifier) { case "*": case "all": diff --git a/EXILED/Exiled.CustomRoles/Commands/Parent.cs b/EXILED/Exiled.CustomRoles/Commands/Parent.cs index fd42b5e497..f64facabec 100644 --- a/EXILED/Exiled.CustomRoles/Commands/Parent.cs +++ b/EXILED/Exiled.CustomRoles/Commands/Parent.cs @@ -41,13 +41,12 @@ public override void LoadGeneratedCommands() RegisterCommand(Give.Instance); RegisterCommand(Info.Instance); RegisterCommand(List.List.Instance); - RegisterCommand(Get.Instance); } /// protected override bool ExecuteParent(ArraySegment arguments, ICommandSender sender, out string response) { - response = "Invalid subcommand! Available: give, info, list, get"; + response = "Invalid subcommand! Available: give, info, list"; return false; } } diff --git a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj index cd1a8b4769..78b2030580 100644 --- a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj +++ b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj @@ -49,4 +49,4 @@ if [[ ! -z "$EXILED_DEV_REFERENCES" ]]; then cp "$(OutputPath)$(AssemblyName).dll" "$EXILED_DEV_REFERENCES/Plugins/"; fi - \ No newline at end of file + diff --git a/EXILED/Exiled.Events/Commands/TpsCommand.cs b/EXILED/Exiled.Events/Commands/TpsCommand.cs index 14c0def05e..722de3b61e 100644 --- a/EXILED/Exiled.Events/Commands/TpsCommand.cs +++ b/EXILED/Exiled.Events/Commands/TpsCommand.cs @@ -15,6 +15,7 @@ namespace Exiled.Events.Commands /// /// Command for showing current server TPS. /// + [CommandHandler(typeof(RemoteAdminCommandHandler))] [CommandHandler(typeof(GameConsoleCommandHandler))] public class TpsCommand : ICommand { @@ -30,7 +31,7 @@ public class TpsCommand : ICommand /// public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) { - double diff = Server.SmoothTps / Server.MaxTps; + double diff = Server.Tps / Server.MaxTps; string color = diff switch { > 0.9 => "green", @@ -38,7 +39,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s _ => "red" }; - response = $"{Server.SmoothTps}/{Server.MaxTps}"; + response = $"{Server.Tps}/{Server.MaxTps}"; return true; } } diff --git a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs index abd2f4877f..a8b986c171 100644 --- a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs @@ -7,70 +7,39 @@ namespace Exiled.Events.EventArgs.Cassie { - using System; - using System.Text; - - using Exiled.API.Features.Pools; - using global::Cassie; using Interfaces; - using Subtitles; /// /// Contains all the information after sending a C.A.S.S.I.E. message. /// public class SendingCassieMessageEventArgs : IDeniableEvent { - private readonly CassieAnnouncement announcement; - private readonly CassieTtsPayload payload; - - private string customSubtitles; - private float glitchScale; - /// /// Initializes a new instance of the class. /// - /// The announcement to populate all properties from. - /// - /// + /// + /// + /// + /// + /// + /// + /// + /// /// - public SendingCassieMessageEventArgs(CassieAnnouncement annc, bool isAllowed = true) + /// + /// + /// + /// + /// + /// + /// Indicates whether the event can be executed. + public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise, bool customAnnouncement, string customSubtitles, bool isAllowed = true) { - announcement = annc; - payload = annc.Payload; - - Words = payload.Content; - switch (payload.SubtitleSource) - { - case CassieTtsPayload.SubtitleMode.None: - case CassieTtsPayload.SubtitleMode.Automatic: - CustomSubtitles = string.Empty; - break; - case CassieTtsPayload.SubtitleMode.Custom: - CustomSubtitles = payload._customSubtitle; - break; - case CassieTtsPayload.SubtitleMode.FromTranslation: - StringBuilder builder = StringBuilderPool.Pool.Get(); - SubtitleController controller = SubtitleController.Singleton; - - foreach (SubtitlePart part in payload._subtitleMessage.SubtitleParts) - { - Subtitle subtitle = controller.Subtitles[part.Subtitle]; - builder.Append(controller.GetTranslation(subtitle)); - } - - CustomSubtitles = StringBuilderPool.Pool.ToStringReturn(builder); - - break; - default: - CustomSubtitles = string.Empty; - break; - } - - MakeHold = payload.PlayBackground; - GlitchScale = annc.GlitchScale; - MakeNoise = annc.GlitchScale is not 0; - SubtitleSource = payload.SubtitleSource; - + Words = words; + CustomSubtitles = customSubtitles; + MakeHold = makeHold; + MakeNoise = makeNoise; + IsCustomAnnouncement = customAnnouncement; IsAllowed = isAllowed; } @@ -82,38 +51,13 @@ public SendingCassieMessageEventArgs(CassieAnnouncement annc, bool isAllowed = t /// /// Gets or sets the message subtitles. /// - public string CustomSubtitles - { - get => customSubtitles; - set - { - if (customSubtitles != value) - SubtitleSource = CassieTtsPayload.SubtitleMode.Custom; - - customSubtitles = value; - } - } + public string CustomSubtitles { get; set; } /// /// Gets or sets a value indicating whether the message should be held. /// public bool MakeHold { get; set; } - /// - /// Gets or sets a value controlling how glitchy this CASSIE message is. - /// - public float GlitchScale - { - get => glitchScale; - set - { - if (!MakeNoise && value is not 0) - MakeNoise = true; - - glitchScale = value; - } - } - /// /// Gets or sets a value indicating whether the message should make noise. /// @@ -125,50 +69,8 @@ public float GlitchScale public bool IsAllowed { get; set; } /// - /// Gets or sets a value indicating whether the event can be executed. + /// Gets or sets a value indicating whether the message can be sent. /// - [Obsolete("Useless and will be removed in Exiled 10.")] public bool IsCustomAnnouncement { get; set; } - - /// - /// Gets or sets a value indicating where the subtitles for this message came from. - /// - public CassieTtsPayload.SubtitleMode SubtitleSource { get; set; } - - /// - /// Gets a consisting of all properties in this event. - /// - public CassieAnnouncement Announcement - { - get - { - CassieTtsPayload newPayload; - - // I love readonly fields :) - if (SubtitleSource is CassieTtsPayload.SubtitleMode.FromTranslation) - { - newPayload = new CassieTtsPayload(Words, MakeHold, payload._subtitleMessage.SubtitleParts); - } - else - { - if (SubtitleSource is CassieTtsPayload.SubtitleMode.Automatic) - newPayload = new CassieTtsPayload(Words, true, MakeHold); - else - newPayload = new CassieTtsPayload(Words, CustomSubtitles, MakeHold); - } - - return announcement switch - { - CassieScpTerminationAnnouncement => - - // this is disabled via patch b/c termination messages are not modifiable at the stage the SendCassieMessage patch is in. - throw new InvalidOperationException("SendCassieMessage was called for a SCP termination message!"), - - CassieWaveAnnouncement waveAnnc => new CassieWaveAnnouncement(waveAnnc.Wave, newPayload), - Cassie079RecontainAnnouncement recontainAnnc => new Cassie079RecontainAnnouncement(recontainAnnc._callback, false, newPayload), - _ => new CassieAnnouncement(newPayload, 0, GlitchScale / (API.Features.Warhead.IsDetonated ? 2F : 1F) * (MakeNoise ? 1F : 0F)), - }; - } - } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs deleted file mode 100644 index fdd41cef5b..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Interfaces -{ - using Exiled.API.Features.Items; - - /// - /// Represents all events related to the marshmallow man. - /// - public interface IMarshmallowEvent : IItemEvent - { - /// - /// Gets the marshmallow item related to this event. - /// - public Marshmallow Marshmallow { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs deleted file mode 100644 index 616ad8f3e5..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Interfaces -{ - /// - /// Represents all events related to SCP-127. - /// - public interface IScp127Event : IItemEvent - { - /// - /// Gets the SCP-127 instance, related to this event. - /// - public API.Features.Items.Scp127 Scp127 { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs index acb2463878..1d6dcf3add 100644 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs @@ -14,7 +14,7 @@ namespace Exiled.Events.EventArgs.Interfaces /// /// Event args used for all related events. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public interface IScp1507Event : IPlayerEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs index fc62383340..d8a5537257 100644 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs @@ -12,7 +12,7 @@ namespace Exiled.Events.EventArgs.Interfaces /// /// Defines the base contract for all related events. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public interface IScp559Event : IExiledEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs deleted file mode 100644 index 8e491ee0b1..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs +++ /dev/null @@ -1,50 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Item -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.MarshmallowMan; - - /// - /// Contains all information before a marshmallow man punches. - /// - public class CacklingEventArgs : IMarshmallowEvent, IDeniableEvent - { - /// - /// Initializes a new instance of the class. - /// - /// The marshmallow item of the player cackling. - /// Whether the player is allowed to cackle. - public CacklingEventArgs(MarshmallowItem marshmallow, bool isAllowed = true) - { - Marshmallow = Item.Get(marshmallow); - Player = Marshmallow.Owner; - IsAllowed = isAllowed; - } - - /// - /// Gets the player cackling. - /// - public Player Player { get; } - - /// - public API.Features.Items.Item Item => Marshmallow; - - /// - /// Gets the marshmallow item of the player cackling. - /// - public Marshmallow Marshmallow { get; } - - /// - /// Gets or sets a value indicating whether the player is allowed to cackle. - /// - public bool IsAllowed { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs deleted file mode 100644 index d2d927d95a..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs +++ /dev/null @@ -1,50 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Item -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.MarshmallowMan; - - /// - /// Contains all information before a marshmallow man punches. - /// - public class PunchingEventArgs : IMarshmallowEvent, IDeniableEvent - { - /// - /// Initializes a new instance of the class. - /// - /// The marshmallow item of the player attacking. - /// Whether the player is allowed to punch. - public PunchingEventArgs(MarshmallowItem marshmallow, bool isAllowed = true) - { - Marshmallow = Item.Get(marshmallow); - Player = Marshmallow.Owner; - IsAllowed = isAllowed; - } - - /// - /// Gets the player punching. - /// - public Player Player { get; } - - /// - public Item Item => Marshmallow; - - /// - /// Gets the marshmallow item of the player punching. - /// - public Marshmallow Marshmallow { get; } - - /// - /// Gets or sets a value indicating whether the punch is allowed. - /// - public bool IsAllowed { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs index d8d38cc474..4c43eb1df8 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs @@ -7,13 +7,15 @@ namespace Exiled.Events.EventArgs.Map { - using System; - using API.Features; using API.Features.DamageHandlers; using API.Features.Roles; + using Interfaces; + using CustomAttackerHandler = API.Features.DamageHandlers.AttackerDamageHandler; + using DamageHandlerBase = PlayerStatsSystem.DamageHandlerBase; + /// /// Contains all information before C.A.S.S.I.E announces an SCP termination. /// @@ -25,14 +27,16 @@ public class AnnouncingScpTerminationEventArgs : IAttackerEvent, IDeniableEvent /// /// /// - /// - /// + /// + /// /// - public AnnouncingScpTerminationEventArgs(Player scp, string terminationCause) + public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHandlerBase) { Player = scp; Role = scp.Role; - TerminationCause = terminationCause; + DamageHandler = new CustomDamageHandler(scp, damageHandlerBase); + Attacker = DamageHandler.BaseIs(out CustomAttackerHandler customAttackerHandler) ? customAttackerHandler.Attacker : null; + TerminationCause = damageHandlerBase.CassieDeathAnnouncement.Announcement; IsAllowed = true; } @@ -54,13 +58,11 @@ public AnnouncingScpTerminationEventArgs(Player scp, string terminationCause) /// /// Gets the player who killed the SCP. /// - [Obsolete("Attacker can no longer be acquired for this event. This will be readded in a different event.")] public Player Attacker { get; } /// /// Gets or sets the . /// - [Obsolete("DamageHandler can no longer be acquired for this event. This will be readded in a different event.")] public CustomDamageHandler DamageHandler { get; set; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs index 038a3e16c4..168a0f578e 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs @@ -18,6 +18,8 @@ namespace Exiled.Events.EventArgs.Player /// public class ReceivingEffectEventArgs : IPlayerEvent, IDeniableEvent { + private byte intensity; + /// /// Initializes a new instance of the class. /// @@ -30,9 +32,9 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int { Player = player; Effect = effect; - Intensity = intensity; + this.intensity = intensity; CurrentIntensity = currentIntensity; - Duration = intensity is 0 ? 0 : duration; + Duration = duration; } /// @@ -51,9 +53,20 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int public float Duration { get; set; } = 0; /// - /// Gets or sets the value of the new intensity of the effect. + /// Gets or sets the value of the new intensity of the effect. Setting this to 0 is the same as setting IsAllowed to + /// . /// - public byte Intensity { get; set; } + public byte Intensity + { + get => intensity; + set + { + intensity = value; + + if (intensity == 0) + IsAllowed = false; + } + } /// /// Gets the value of the intensity of this effect on the player. diff --git a/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs deleted file mode 100644 index 6dce01109c..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs +++ /dev/null @@ -1,41 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Player -{ - using API.Features; - using API.Features.Items; - using Interfaces; - using InventorySystem.Items.Usables.Scp1576; - - /// - /// Contains all information after a SCP-1576 transmission has ended. - /// - public class Scp1576TransmissionEndedEventArgs : IPlayerEvent - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - public Scp1576TransmissionEndedEventArgs(Player player, Scp1576Item scp1576Item) - { - Player = player; - Scp1576 = Item.Get(scp1576Item); - } - - /// - /// Gets the that the transmission ended for. - /// - public Player Player { get; } - - /// - /// Gets the instance. - /// - public Exiled.API.Features.Items.Scp1576 Scp1576 { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs index c6aeed7ffb..e25e9fd728 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs @@ -28,14 +28,10 @@ public class UsedItemEventArgs : IPlayerEvent, IUsableEvent /// /// /// - /// - /// - /// - public UsedItemEventArgs(ReferenceHub player, UsableItem item, bool causedByHolstering) + public UsedItemEventArgs(ReferenceHub player, UsableItem item) { Player = Player.Get(player); - Usable = Item.Get(item) as Usable; - CausedByHolstering = causedByHolstering; + Usable = Item.Get(item) is Usable usable ? usable : null; } /// @@ -50,11 +46,5 @@ public UsedItemEventArgs(ReferenceHub player, UsableItem item, bool causedByHols /// Gets the player who used the item. /// public Player Player { get; } - - /// - /// Gets a value indicating whether this event was triggered by a player switching items (true) or by waiting after using the item (false). - /// - /// Use this value if you wish to keep the bug where you could switch items quickly to skip this event. - public bool CausedByHolstering { get; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs deleted file mode 100644 index 533ccbb5ce..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs +++ /dev/null @@ -1,51 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp127 -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Contains all information before SCP-127 gains experience. - /// - public class GainedExperienceEventArgs : IScp127Event - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - public GainedExperienceEventArgs(Scp127 scp127, float experience) - { - Scp127 = scp127; - Experience = experience; - Tier = Scp127.TierManagerModule.GetTierForExp(Experience + Scp127.Experience); - } - - /// - public Player Player => Scp127.Owner; - - /// - public Item Item => Scp127; - - /// - public Scp127 Scp127 { get; } - - /// - /// Gets the experience that SCP-127 has gained. - /// - public float Experience { get; } - - /// - /// Gets the tier. - /// - public Scp127Tier Tier { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs deleted file mode 100644 index 6a1d7b738b..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs +++ /dev/null @@ -1,59 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp127 -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Contains all information before SCP-127 gains experience. - /// - public class GainingExperienceEventArgs : IScp127Event, IDeniableEvent - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - public GainingExperienceEventArgs(Scp127 scp127, float experience, bool isAllowed = true) - { - Scp127 = scp127; - Experience = experience; - IsAllowed = isAllowed; - } - - /// - public Player Player => Scp127.Owner; - - /// - public Item Item => Scp127; - - /// - public Scp127 Scp127 { get; } - - /// - public bool IsAllowed { get; set; } - - /// - /// Gets or sets the gaining experience. - /// - public float Experience { get; set; } - - /// - /// Gets or sets the new tier. - /// - public Scp127Tier Tier - { - get => Scp127.TierManagerModule.GetTierForExp(Experience + Scp127.Experience); - set => Experience = Scp127.TierManagerModule.GetExpForTier(value) - Scp127.Experience; - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs deleted file mode 100644 index 10810403d5..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs +++ /dev/null @@ -1,52 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp127 -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Contains all information after SCP-127 voice line is played. - /// - public class TalkedEventArgs : IScp127Event - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - public TalkedEventArgs(Scp127 scp127, Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority voiceLinePriority) - { - Scp127 = scp127; - VoiceLine = voiceLine; - Priority = voiceLinePriority; - } - - /// - public Player Player => Scp127.Owner; - - /// - public Item Item => Scp127; - - /// - public Scp127 Scp127 { get; } - - /// - /// Gets a voice line which is played. - /// - public Scp127VoiceLinesTranslation VoiceLine { get; } - - /// - /// Gets a priority for this play. - /// - public Scp127VoiceTriggerBase.VoiceLinePriority Priority { get; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs deleted file mode 100644 index b8934566a8..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs +++ /dev/null @@ -1,57 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp127 -{ - using Exiled.API.Features; - using Exiled.API.Features.Items; - using Exiled.Events.EventArgs.Interfaces; - using InventorySystem.Items.Firearms.Modules.Scp127; - - /// - /// Contains all information before SCP-127 voice line is played. - /// - public class TalkingEventArgs : IScp127Event, IDeniableEvent - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - public TalkingEventArgs(Scp127 scp127, Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority voiceLinePriority, bool isAllowed = true) - { - Scp127 = scp127; - VoiceLine = voiceLine; - Priority = voiceLinePriority; - IsAllowed = isAllowed; - } - - /// - public Player Player => Scp127.Owner; - - /// - public Item Item => Scp127; - - /// - public Scp127 Scp127 { get; } - - /// - public bool IsAllowed { get; set; } - - /// - /// Gets or sets a voice line which is played. - /// - public Scp127VoiceLinesTranslation VoiceLine { get; set; } - - /// - /// Gets or sets a priority for this play. - /// - public Scp127VoiceTriggerBase.VoiceLinePriority Priority { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs index c6ea947e55..c58330e252 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs @@ -18,7 +18,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 attacks door. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class AttackingDoorEventArgs : IScp1507Event, IDeniableEvent, IDoorEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs index 7ab56f98e2..ae5ebb8450 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs @@ -16,7 +16,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 screams. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class ScreamingEventArgs : IScp1507Event, IDeniableEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs index 5cc50f9352..376eba5abf 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs @@ -19,7 +19,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before flamingos get spawned. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class SpawningFlamingosEventArgs : IDeniableEvent, IPlayerEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs index 10b713052e..0121d02d95 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 screams. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class UsingTapeEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs deleted file mode 100644 index d4935e6c92..0000000000 --- a/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs +++ /dev/null @@ -1,40 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Scp2536 -{ - using Christmas.Scp2536; - using Exiled.API.Features; - using Exiled.Events.EventArgs.Interfaces; - - /// - /// Contains all information after SCP-2536 chooses target for spawning. - /// - public class FoundPositionEventArgs : IPlayerEvent - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - public FoundPositionEventArgs(Player player, Scp2536Spawnpoint spawnpoint) - { - Player = player; - Spawnpoint = spawnpoint; - } - - /// - /// Gets the player near whom SCP-2536 will spawn. - /// - public Player Player { get; } - - /// - /// Gets or sets the spawn point where SCP will spawn. - /// - public Scp2536Spawnpoint Spawnpoint { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs index 1a4a7408dc..b8b99f9ac9 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs @@ -15,7 +15,7 @@ namespace Exiled.Events.EventArgs.Scp559 /// /// Contains all information before a player interacts with SCP-559. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class InteractingScp559EventArgs : IScp559Event, IDeniableEvent, IPlayerEvent { /// @@ -23,11 +23,12 @@ public class InteractingScp559EventArgs : IScp559Event, IDeniableEvent, IPlayerE /// /// /// - public InteractingScp559EventArgs(Scp559 scp559, Player player) + /// + public InteractingScp559EventArgs(Scp559 scp559, Player player, bool isAllowed = true) { Player = player; Scp559 = scp559; - IsAllowed = scp559.RemainingSlices > 0 && PlayerRoles.PlayerRolesUtils.IsHuman(player.Role.Type); + IsAllowed = isAllowed; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs index c83baddd2c..6e3a81f06a 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs @@ -16,7 +16,7 @@ namespace Exiled.Events.EventArgs.Scp559 /// /// Contains all information before SCP-559 spawns. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public class SpawningEventArgs : IDeniableEvent, IScp559Event { /// diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index adae6e21a8..a1bdd040a2 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -21,7 +21,6 @@ namespace Exiled.Events using PlayerRoles.FirstPersonControl.NetworkMessages; using PlayerRoles.Ragdolls; using PlayerRoles.RoleAssign; - using Respawning; using UnityEngine.SceneManagement; using UserSettings.ServerSpecific; @@ -74,7 +73,6 @@ public override void OnEnabled() Handlers.Scp049.ActivatingSense += Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified += Handlers.Internal.Round.OnVerified; Handlers.Map.ChangedIntoGrenade += Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; - Handlers.Warhead.Detonated += Handlers.Internal.Round.OnWarheadDetonated; RoleAssigner.OnPlayersSpawned += Handlers.Server.OnAllPlayersSpawned; CharacterClassManager.OnRoundStarted += Handlers.Server.OnRoundStarted; @@ -97,11 +95,6 @@ public override void OnEnabled() FpcServerPositionDistributor.RoleSyncEvent += Handlers.Internal.Round.OnRoleSyncEvent; - LabApi.Events.Handlers.Scp127Events.Talking += Handlers.Scp127.OnTalking; - LabApi.Events.Handlers.Scp127Events.Talked += Handlers.Scp127.OnTalked; - LabApi.Events.Handlers.Scp127Events.GainingExperience += Handlers.Scp127.OnGainingExperience; - LabApi.Events.Handlers.Scp127Events.GainExperience += Handlers.Scp127.OnGainedExperience; - ServerConsole.ReloadServerName(); } @@ -142,11 +135,6 @@ public override void OnDisabled() LabApi.Events.Handlers.PlayerEvents.UnloadingWeapon -= Handlers.Player.OnUnloadingWeapon; FpcServerPositionDistributor.RoleSyncEvent -= Handlers.Internal.Round.OnRoleSyncEvent; - - LabApi.Events.Handlers.Scp127Events.Talking -= Handlers.Scp127.OnTalking; - LabApi.Events.Handlers.Scp127Events.Talked -= Handlers.Scp127.OnTalked; - LabApi.Events.Handlers.Scp127Events.GainingExperience -= Handlers.Scp127.OnGainingExperience; - LabApi.Events.Handlers.Scp127Events.GainExperience -= Handlers.Scp127.OnGainedExperience; } /// diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 26ff90342a..4cedb7a21e 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -29,7 +29,6 @@ namespace Exiled.Events.Handlers.Internal using InventorySystem.Items.Firearms.Attachments.Components; using InventorySystem.Items.Usables; using InventorySystem.Items.Usables.Scp244.Hypothermia; - using InventorySystem.Items.Usables.Scp330; using Mirror; using PlayerRoles; using PlayerRoles.FirstPersonControl; @@ -109,9 +108,6 @@ public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { if (ev.Role.IsDead() || !ev.Role.IsFpcRole()) ev.IsAllowed = false; - - if (ev.DamageHandlerBase is Exiled.Events.Patches.Fixes.FixMarshmallowManFF fixMarshamllowManFf) - ev.DamageHandlerBase = fixMarshamllowManFf.MarshmallowItem.NewDamageHandler; } /// @@ -140,7 +136,7 @@ public static void OnVerified(VerifiedEventArgs ev) } // Fix bug that player that Join do not receive information about other players Scale - foreach (Player player in ReferenceHub.AllHubs.Select(Player.Get)) + foreach (Player player in Player.Enumerable) { player.SetFakeScale(player.Scale, new List() { ev.Player }); @@ -182,13 +178,6 @@ public static RoleTypeId OnRoleSyncEvent(ReferenceHub viewerHub, ReferenceHub ow return actualRole; } - /// - public static void OnWarheadDetonated() - { - // fix for black candy - CandyBlack.Outcomes.RemoveAll(outcome => outcome is TeleportOutcome); - } - private static void GenerateAttachments() { foreach (FirearmType firearmType in EnumUtils.Values) diff --git a/EXILED/Exiled.Events/Handlers/Item.cs b/EXILED/Exiled.Events/Handlers/Item.cs index b1ca257f09..9ac83aafd3 100644 --- a/EXILED/Exiled.Events/Handlers/Item.cs +++ b/EXILED/Exiled.Events/Handlers/Item.cs @@ -89,16 +89,6 @@ public static class Item /// public static Event JailbirdChangedWearState { get; set; } = new(); - /// - /// Invoked before a marshmallow man punches. - /// - public static Event Punching { get; set; } = new(); - - /// - /// Invoked before a marshmallow man cackles. - /// - public static Event Cackling { get; set; } = new(); - /// /// Called before the Jailbird's is changed. /// @@ -183,17 +173,5 @@ public static class Item /// /// The instance. public static void OnInspectedItem(InspectedItemEventArgs ev) => InspectedItem.InvokeSafely(ev); - - /// - /// Called before a marshmallow man punches. - /// - /// The instance. - public static void OnPunching(PunchingEventArgs ev) => Punching.InvokeSafely(ev); - - /// - /// Called before a marshmallow man cackles. - /// - /// The instance. - public static void OnCackling(CacklingEventArgs ev) => Cackling.InvokeSafely(ev); } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index 998b54f813..97e6137003 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -621,11 +621,6 @@ public class Player /// public static Event InteractingEmergencyButton { get; set; } = new(); - /// - /// Invoked after transmission has ended. - /// - public static Event Scp1576TransmissionEnded { get; set; } = new(); - /// /// Called before a player's emotion changed. /// @@ -1361,11 +1356,5 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item /// /// The instance. public static void OnInteractingEmergencyButton(InteractingEmergencyButtonEventArgs ev) => InteractingEmergencyButton.InvokeSafely(ev); - - /// - /// Called after a 1576 transmisiion has ended. - /// - /// The instance. - public static void OnScp1576TransmissionEnded(Scp1576TransmissionEndedEventArgs ev) => Scp1576TransmissionEnded.InvokeSafely(ev); } } diff --git a/EXILED/Exiled.Events/Handlers/Scp127.cs b/EXILED/Exiled.Events/Handlers/Scp127.cs deleted file mode 100644 index b3f86534d3..0000000000 --- a/EXILED/Exiled.Events/Handlers/Scp127.cs +++ /dev/null @@ -1,81 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Handlers -{ - using Exiled.Events.EventArgs.Scp127; - using Exiled.Events.Features; - using LabApi.Events.Arguments.Scp127Events; - -#pragma warning disable SA1623 - /// - /// SCP-127 event handlers. - /// - public static class Scp127 - { - /// - /// Invoked before SCP-127 voice line is played. - /// - public static Event Talking { get; set; } = new(); - - /// - /// Invoked after SCP-127 voice line is played. - /// - public static Event Talked { get; set; } = new(); - - /// - /// Invoked before SCP-127 gains experience. - /// - public static Event GainingExperience { get; set; } = new(); - - /// - /// Invoked after SCP-127 gains experience. - /// - public static Event GainedExperience { get; set; } = new(); - - /// - /// Called before SCP-127 voice line is played. - /// - /// The instance. - public static void OnTalking(Scp127TalkingEventArgs ev) - { - TalkingEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.VoiceLine, ev.Priority, ev.IsAllowed); - Talking.InvokeSafely(eventArgs); - - ev.Priority = eventArgs.Priority; - ev.VoiceLine = eventArgs.VoiceLine; - ev.IsAllowed = eventArgs.IsAllowed; - } - - /// - /// Called after SCP-127 voice line is played. - /// - /// The instance. - public static void OnTalked(Scp127TalkedEventArgs ev) - => Talked.InvokeSafely(new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.VoiceLine, ev.Priority)); - - /// - /// Called before SCP-127 gains experience. - /// - /// The instance. - public static void OnGainingExperience(Scp127GainingExperienceEventArgs ev) - { - GainingExperienceEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.ExperienceGain, ev.IsAllowed); - GainingExperience.InvokeSafely(eventArgs); - - ev.ExperienceGain = eventArgs.Experience; - ev.IsAllowed = eventArgs.IsAllowed; - } - - /// - /// Called after SCP-127 gains experience. - /// - /// The instance. - public static void OnGainedExperience(Scp127GainExperienceEventArgs ev) => - GainedExperience.InvokeSafely(new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.ExperienceGain)); - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Scp1507.cs b/EXILED/Exiled.Events/Handlers/Scp1507.cs index f36b16d633..63e4536d2c 100644 --- a/EXILED/Exiled.Events/Handlers/Scp1507.cs +++ b/EXILED/Exiled.Events/Handlers/Scp1507.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.Handlers /// /// SCP-1507 related events. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public static class Scp1507 { /// diff --git a/EXILED/Exiled.Events/Handlers/Scp2536.cs b/EXILED/Exiled.Events/Handlers/Scp2536.cs index 8c0d272583..3f7dfd1c58 100644 --- a/EXILED/Exiled.Events/Handlers/Scp2536.cs +++ b/EXILED/Exiled.Events/Handlers/Scp2536.cs @@ -21,11 +21,6 @@ public static class Scp2536 /// public static Event FindingPosition { get; set; } = new(); - /// - /// Invoked once SCP-2536 has found a spawn location. - /// - public static Event FoundPosition { get; set; } = new(); - /// /// Invoked before SCP-2536 gives a gift to a player. /// @@ -42,12 +37,6 @@ public static class Scp2536 /// The instance. public static void OnFindingPosition(FindingPositionEventArgs ev) => FindingPosition.InvokeSafely(ev); - /// - /// Called after SCP-2536 chooses a target. - /// - /// The instance. - public static void OnFoundPosition(FoundPositionEventArgs ev) => FoundPosition.InvokeSafely(ev); - /// /// Called before SCP-2536 gives a gift to a player. /// diff --git a/EXILED/Exiled.Events/Handlers/Scp559.cs b/EXILED/Exiled.Events/Handlers/Scp559.cs index 70d5387520..b17f520c9d 100644 --- a/EXILED/Exiled.Events/Handlers/Scp559.cs +++ b/EXILED/Exiled.Events/Handlers/Scp559.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.Handlers /// /// All SCP-559 related events. /// - // [Obsolete("Only availaible for Christmas and AprilFools.")] + [Obsolete("Only availaible for Christmas and AprilFools.")] public static class Scp559 { /// diff --git a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs index 1e7b55e3a8..0cb378ac02 100644 --- a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs +++ b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs @@ -8,61 +8,87 @@ namespace Exiled.Events.Patches.Events.Cassie { using System.Collections.Generic; - using System.Linq; using System.Reflection.Emit; using API.Features.Pools; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Cassie; - using global::Cassie; + using Handlers; + using HarmonyLib; using Respawning; using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Cassie), nameof(Cassie.SendingCassieMessage))] - [HarmonyPatch(typeof(CassieAnnouncementDispatcher), nameof(CassieAnnouncementDispatcher.PlayNewAnnouncement))] + [HarmonyPatch(typeof(RespawnEffectsController), nameof(RespawnEffectsController.PlayCassieAnnouncement))] internal static class SendingCassieMessage { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); - Label skipLabel = generator.DefineLabel(); Label returnLabel = generator.DefineLabel(); - newInstructions[0].WithLabels(skipLabel); - newInstructions.InsertRange( 0, new CodeInstruction[] { + // words new(OpCodes.Ldarg_0), - new(OpCodes.Isinst, typeof(CassieScpTerminationAnnouncement)), - new(OpCodes.Brtrue_S, skipLabel), - new(OpCodes.Ldarg_0), + // makeHold + new(OpCodes.Ldarg_1), + + // makeNoise + new(OpCodes.Ldarg_2), + + // customAnnouncement + new(OpCodes.Ldarg_3), + + // customSubtitles + new(OpCodes.Ldarg_S, 4), // isAllowed new(OpCodes.Ldc_I4_1), - // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(CassieAnnouncement, bool); - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs)).Single(ctor => ctor.GetParameters().Length == 2)), + // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(string, bool, bool, bool, string, bool); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Dup), new(OpCodes.Dup), new(OpCodes.Dup), // Cassie.OnSendingCassieMessage(ev); new(OpCodes.Call, Method(typeof(Cassie), nameof(Cassie.OnSendingCassieMessage))), - // annc = ev.Announcement - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Announcement))), + // words = ev.Words + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Words))), new(OpCodes.Starg_S, 0), + // makeHold = ev.MakeHold + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeHold))), + new(OpCodes.Starg_S, 1), + + // makeNoise = ev.MakeNoise + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeNoise))), + new(OpCodes.Starg_S, 2), + + // customAnnouncement = ev.IsCustomAnnouncement + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsCustomAnnouncement))), + new(OpCodes.Starg_S, 3), + + // customSubtitles = ev.CustomSubtitles + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.CustomSubtitles))), + new(OpCodes.Starg_S, 4), + // if (!IsAllowed) // return; new(OpCodes.Callvirt, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsAllowed))), diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs b/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs deleted file mode 100644 index fec7811ecf..0000000000 --- a/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs +++ /dev/null @@ -1,65 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Patches.Events.Item -{ - using System.Collections.Generic; - using System.Reflection.Emit; - - using Exiled.API.Features; - using Exiled.API.Features.Pools; - using Exiled.Events.Attributes; - using Exiled.Events.EventArgs.Item; - using HarmonyLib; - using InventorySystem.Items.MarshmallowMan; - - using static HarmonyLib.AccessTools; - - /// - /// Patch the . - /// Adds the event. - /// - [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Cackling))] - [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCackle))] - public class Cackling - { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - List newInstructions = ListPool.Pool.Get(instructions); - - Label retLabel = generator.DefineLabel(); - - int offset = 1; - int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; - - newInstructions.InsertRange(index, new[] - { - // this; - new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), - - // true - new(OpCodes.Ldc_I4_1), - - // ev = new CacklingEventArgs(MarshmallowItem, bool); - new(OpCodes.Newobj, Constructor(typeof(CacklingEventArgs), new[] { typeof(MarshmallowItem), typeof(bool) })), - new(OpCodes.Dup), - new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnCackling))), - - // if (!ev.IsAllowed) return - new(OpCodes.Callvirt, PropertyGetter(typeof(CacklingEventArgs), nameof(CacklingEventArgs.IsAllowed))), - new(OpCodes.Brfalse_S, retLabel), - }); - - newInstructions[newInstructions.Count - 1].WithLabels(retLabel); - - for (int z = 0; z < newInstructions.Count; z++) - yield return newInstructions[z]; - - ListPool.Pool.Return(newInstructions); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs b/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs deleted file mode 100644 index 15c74b57b1..0000000000 --- a/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs +++ /dev/null @@ -1,65 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Patches.Events.Item -{ - using System.Collections.Generic; - using System.Reflection.Emit; - - using Exiled.API.Features; - using Exiled.API.Features.Pools; - using Exiled.Events.Attributes; - using Exiled.Events.EventArgs.Item; - using HarmonyLib; - using InventorySystem.Items.MarshmallowMan; - - using static HarmonyLib.AccessTools; - - /// - /// Patch the . - /// Adds the event. - /// - [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Punching))] - [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCmd))] - public class Punching - { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - List newInstructions = ListPool.Pool.Get(instructions); - - Label retLabel = generator.DefineLabel(); - - int offset = 1; - int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; - - newInstructions[^1].WithLabels(retLabel); - - newInstructions.InsertRange(index, new[] - { - // this; - new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), - - // true - new(OpCodes.Ldc_I4_1), - - // ev = new PunchingEventArgs(MarshmallowItem, bool); - new(OpCodes.Newobj, Constructor(typeof(PunchingEventArgs), new[] { typeof(MarshmallowItem), typeof(bool) })), - new(OpCodes.Dup), - new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnPunching))), - - // if (!ev.IsAllowed) return - new(OpCodes.Callvirt, PropertyGetter(typeof(PunchingEventArgs), nameof(PunchingEventArgs.IsAllowed))), - new(OpCodes.Brfalse_S, retLabel), - }); - - for (int z = 0; z < newInstructions.Count; z++) - yield return newInstructions[z]; - - ListPool.Pool.Return(newInstructions); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs index 3033a0327d..0d53ebeefb 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs @@ -7,7 +7,6 @@ namespace Exiled.Events.Patches.Events.Map { - using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; @@ -18,12 +17,11 @@ namespace Exiled.Events.Patches.Events.Map using Exiled.Events.EventArgs.Map; using HarmonyLib; using Respawning.Announcements; - using Subtitles; using static HarmonyLib.AccessTools; /// - /// Patches and + /// Patches and /// to add event. /// [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] @@ -32,8 +30,8 @@ internal static class AnnouncingChaosEntrance { private static IEnumerable TargetMethods() { - yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncement)); - yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncement)); + yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncementString)); + yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncementString)); } private static IEnumerable Transpiler(IEnumerable instruction, ILGenerator generator) @@ -72,9 +70,6 @@ private static IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncement))] + [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncementString))] internal static class AnnouncingNtfEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -40,8 +39,8 @@ private static IEnumerable Transpiler(IEnumerable instruction.Calls(Method(typeof(UnitNamingRule), nameof(UnitNamingRule.TranslateToCassie)))) + offset; + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Stloc_3) + offset; newInstructions.InsertRange( index, @@ -51,10 +50,10 @@ private static IEnumerable Transpiler(IEnumerable]*?>"), new(OpCodes.Ldsfld, Field(typeof(string), nameof(string.Empty))), new(OpCodes.Call, Method(typeof(Regex), nameof(Regex.Replace), new System.Type[] { typeof(string), typeof(string), typeof(string) })), @@ -64,9 +63,9 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncement))] + [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncementString))] internal static class AnnouncingNtfMiniEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -35,17 +35,15 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Stloc_1) + 1; - newInstructions.InsertRange( - index, + 0, new CodeInstruction[] { // WaveAnnouncementBase new(OpCodes.Ldarg_0), // scpsLeft - new(OpCodes.Ldloc_1), + new(OpCodes.Ldloc_0), // null new(OpCodes.Ldnull), @@ -68,7 +66,7 @@ private static IEnumerable Transpiler(IEnumerable /// Patches - /// . + /// . /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingScpTermination))] - [HarmonyPatch(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.OnStartedPlaying))] + [HarmonyPatch(typeof(NineTailedFoxAnnouncer), nameof(NineTailedFoxAnnouncer.AnnounceScpTermination))] internal static class AnnouncingScpTermination { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); - LocalBuilder cause = generator.DeclareLocal(typeof(string)); - LocalBuilder enumerator = generator.DeclareLocal(typeof(IEnumerator)); - - ExceptionBlock beginTry = new(ExceptionBlockType.BeginExceptionBlock); - ExceptionBlock beginFinally = new(ExceptionBlockType.BeginFinallyBlock); - ExceptionBlock endFinally = new(ExceptionBlockType.EndExceptionBlock); + LocalBuilder ev = generator.DeclareLocal(typeof(AnnouncingScpTerminationEventArgs)); Label ret = generator.DefineLabel(); - Label entryLabel = generator.DefineLabel(); - Label loopLabel = generator.DefineLabel(); - Label leaveLabel = generator.DefineLabel(); - Label endFinallyLabel = generator.DefineLabel(); - - int offset = -1; - int index = newInstructions.FindIndex(i => i.LoadsField(Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts)))) + offset; - - newInstructions.RemoveRange(index, 2); - newInstructions.Insert(index, new CodeInstruction(OpCodes.Ldloc_S, cause)); - newInstructions[0].WithLabels(leaveLabel); + int offset = -4; + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Newobj && (ConstructorInfo)i.operand == GetDeclaredConstructors(typeof(LabApi.Events.Arguments.ServerEvents.CassieQueuingScpTerminationEventArgs))[0]) + offset; newInstructions.InsertRange( - 0, + index, new[] - { - new(OpCodes.Ldarg_0), - new(OpCodes.Ldfld, Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts))), - new(OpCodes.Stloc_S, cause), - new(OpCodes.Ldarg_0), - new(OpCodes.Callvirt, PropertyGetter(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.Victims))), - new(OpCodes.Callvirt, Method(typeof(IEnumerable), nameof(IEnumerable.GetEnumerator))), - new(OpCodes.Stloc_S, enumerator), - - // start of try - new CodeInstruction(OpCodes.Br_S, entryLabel).WithBlocks(beginTry), - - // start of loop - new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(loopLabel), - new(OpCodes.Callvirt, PropertyGetter(typeof(IEnumerator), nameof(IEnumerator.Current))), - new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(Footprint) })), - new(OpCodes.Ldloc_S, cause), - new(OpCodes.Newobj, Constructor(typeof(AnnouncingScpTerminationEventArgs), new[] { typeof(Player), typeof(string) })), - new(OpCodes.Dup), - new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), - new(OpCodes.Stloc_S, cause), - - // entry point - new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(entryLabel), - new(OpCodes.Callvirt, Method(typeof(IEnumerator), nameof(IEnumerator.MoveNext))), - new(OpCodes.Brtrue_S, loopLabel), - - // end of loop - new(OpCodes.Leave, leaveLabel), - - // begin finally - new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithBlocks(beginFinally), - new(OpCodes.Brfalse, endFinallyLabel), - new(OpCodes.Ldloc_S, enumerator), - new(OpCodes.Callvirt, Method(typeof(IDisposable), nameof(IDisposable.Dispose))), - - // end of finally - new CodeInstruction(OpCodes.Endfinally).WithLabels(endFinallyLabel).WithBlocks(endFinally), - }); + { + // Player.Get(scp) + new CodeInstruction(OpCodes.Ldarg_0), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), + + // hit + new(OpCodes.Ldarg_1), + + // AnnouncingScpTerminationEventArgs ev = new(Player, DamageHandlerBase) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(AnnouncingScpTerminationEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev.LocalIndex), + + // Map.OnAnnouncingScpTermination(ev) + new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), + + // if (!ev.IsAllowed) + // return; + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, ret), + + // hit = ev.DamageHandler.Base + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.DamageHandler))), + new(OpCodes.Callvirt, PropertyGetter(typeof(CustomDamageHandler), nameof(CustomDamageHandler.Base))), + new(OpCodes.Starg, 1), + + // announcement = ev.TerminationCause + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), + new(OpCodes.Stloc_0), + }); newInstructions[newInstructions.Count - 1].labels.Add(ret); diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs new file mode 100644 index 0000000000..7193f8d17f --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs @@ -0,0 +1,68 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Map +{ + using System.Collections.Generic; + using System.Reflection; + using System.Reflection.Emit; + using System.Text; + + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Map; + using HarmonyLib; + using Respawning.Announcements; + + using static HarmonyLib.AccessTools; + + /// + /// Patches to prevent cassie from playing empty string. + /// + [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingNtfEntrance))] + [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] + [HarmonyPatch(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.PlayAnnouncement))] + internal static class AnnouncingTeamEntrance + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label returnLabel = generator.DefineLabel(); + + // the instruction that sends subtitles is called before stringReturn is created (and thus checked) so we need to move it so that empty (or disallowed) message's subtitles are not sent. + // this removes the Ldarg_0 and the CallVirt + int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.SendSubtitles)))); + CodeInstruction sendSubtitlesInstruction = newInstructions[index]; + newInstructions.RemoveRange(index - 2, 3); + + index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldsfld); + + newInstructions.InsertRange(index, new[] + { + // if (stringReturn == "") + // return; + new(OpCodes.Ldloc_S, 4), + new(OpCodes.Ldstr, string.Empty), + new(OpCodes.Ceq), + new(OpCodes.Brtrue_S, returnLabel), + + // send subtitles before cassie message, but after our check. + new(OpCodes.Ldarg_0), + new(OpCodes.Ldarg_1), + sendSubtitlesInstruction, + }); + + newInstructions[newInstructions.Count - 1].labels.Add(returnLabel); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs index 4af8bd4e11..b379bdec1a 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs @@ -89,13 +89,14 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(RoomConnectorSpawnpointBase), nameof(RoomConnectorSpawnpointBase.SetupAllRoomConnectors)))); - List GateAArmory, + + /// + /// Represents the door in . + /// + HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/EffectType.cs b/EXILED/Exiled.API/Enums/EffectType.cs index e70e273e77..9bed0519c9 100644 --- a/EXILED/Exiled.API/Enums/EffectType.cs +++ b/EXILED/Exiled.API/Enums/EffectType.cs @@ -216,7 +216,7 @@ public enum EffectType /// /// Makes you a marshmallow guy. /// - [Obsolete("Not functional in-game")] + // [Obsolete("Not functional in-game")] Marshmallow, /// @@ -261,27 +261,27 @@ public enum EffectType Blurred, /// - /// Makes you a flamingo. + /// Makes you a flamingo . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] BecomingFlamingo, /// - /// Makes you a Child after eating Cake. + /// Makes you a Child after eating Cake . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] Scp559, /// - /// Scp956 found you. + /// Scp956 found you . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] Scp956Target, /// - /// you are snowed. + /// you are snowed . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] Snowed, /// @@ -317,78 +317,93 @@ public enum EffectType /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] Metal, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] OrangeCandy, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] OrangeWitness, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] Prismatic, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] SlowMetabolism, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] Spicy, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + // [Obsolete("Only availaible for Halloween or Christmas.")] SugarCrave, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] SugarHigh, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] SugarRush, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] TemporaryBypass, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] TraumatizedByEvil, /// /// . /// - // [Obsolete("Only availaible for Halloween.")] + [Obsolete("Only availaible for Halloween.")] WhiteCandy, /// /// . /// Scp1509Resurrected, + + /// + /// . + /// + FocusedVision, + + /// + /// . + /// + AnomalousRegeneration, + + /// + /// . + /// + AnomalousTarget, } } diff --git a/EXILED/Exiled.API/Enums/GlassType.cs b/EXILED/Exiled.API/Enums/GlassType.cs index 85c068108f..fef4d59f44 100644 --- a/EXILED/Exiled.API/Enums/GlassType.cs +++ b/EXILED/Exiled.API/Enums/GlassType.cs @@ -84,5 +84,10 @@ public enum GlassType /// Represents the window in . /// GateAArmory, + + /// + /// Represents the window in + /// + HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/PrefabType.cs b/EXILED/Exiled.API/Enums/PrefabType.cs index 6a52ce7995..43936f1d80 100644 --- a/EXILED/Exiled.API/Enums/PrefabType.cs +++ b/EXILED/Exiled.API/Enums/PrefabType.cs @@ -417,5 +417,47 @@ public enum PrefabType [Prefab(213466224, "SCP-939 Ragdoll Halloween")] Scp939RagdollHalloween, + + [Prefab(689741320, "SCP-559 Cake")] + Scp559Cake, + + [Prefab(2657863153, "SCP-956")] + Scp956, + + [Prefab(1205960739, "SCP-2536 Tree")] + Scp2536, + + [Prefab(2102014206, "Snowpile")] + Snowpile, + + [Prefab(3401975113, "Scp018Projectile Christmas")] + Scp018ProjectileChristmas, + + [Prefab(3223468476, "SnowballProjectile")] + SnowballProjectile, + + [Prefab(296717882, "CoalPickup")] + CoalPickup, + + [Prefab(409273101, "TapePlayerPickup")] + Scp1507TapePickup, + + [Prefab(3971391978, "Scp021JPickup")] + Scp021JPickup, + + [Prefab(142820664, "CoalProjectile")] + CoalProjectile, + + [Prefab(2405470903, "Scp2536Projectile")] + Scp2536Projectile, + + [Prefab(1496232901, "SCP-173 Ragdoll Variant")] + Scp173RagdollChristmas, + + [Prefab(6069361, "SnowPoop - TantrumObj")] + SnowTantrum, + + [Prefab(3654754970, "SCP-1507 Ragdoll")] + Scp1507Ragdoll, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/ProjectileType.cs b/EXILED/Exiled.API/Enums/ProjectileType.cs index a8072ed48e..2d95210924 100644 --- a/EXILED/Exiled.API/Enums/ProjectileType.cs +++ b/EXILED/Exiled.API/Enums/ProjectileType.cs @@ -51,21 +51,21 @@ public enum ProjectileType /// Coal. /// Used by . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] Coal, /// /// SpecialCoal. /// Used by . /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] SpecialCoal, /// /// Snowball. /// Used by . /// - [Obsolete("Only availaible for Christmas.")] + // [Obsolete("Only availaible for Christmas.")] Snowball, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/RoomType.cs b/EXILED/Exiled.API/Enums/RoomType.cs index 0b7737c193..6dceeea6e2 100644 --- a/EXILED/Exiled.API/Enums/RoomType.cs +++ b/EXILED/Exiled.API/Enums/RoomType.cs @@ -353,5 +353,10 @@ public enum RoomType /// Heavy Containment Zone's straight hall room with lava. /// HczDss12 = HczIncineratorWayside, + + /// + /// Heavy Containment Zone's T-intersection with a ramp in it. + /// + HczLoadingBay, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/Side.cs b/EXILED/Exiled.API/Enums/Side.cs index 5e9c063be7..5accace2f3 100644 --- a/EXILED/Exiled.API/Enums/Side.cs +++ b/EXILED/Exiled.API/Enums/Side.cs @@ -52,5 +52,10 @@ public enum Side /// No team. Same as . /// None, + + /// + /// Contains and . Same as . + /// + Flamingos, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Exiled.API.csproj b/EXILED/Exiled.API/Exiled.API.csproj index 31fe36e002..70f81bf0d1 100644 --- a/EXILED/Exiled.API/Exiled.API.csproj +++ b/EXILED/Exiled.API/Exiled.API.csproj @@ -34,6 +34,7 @@ + diff --git a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs index 95dfc33727..6fde63477d 100644 --- a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs +++ b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs @@ -204,6 +204,13 @@ public static DamageType GetDamageType(DamageHandlerBase damageHandlerBase) Log.Warn($"{nameof(DamageTypeExtensions)}.{nameof(damageHandlerBase)}: No matching {nameof(DamageType)} for {nameof(UniversalDamageHandler)} with ID {translation.Id}, type will be reported as {DamageType.Unknown}. Report this to EXILED Devs."); return DamageType.Unknown; } + + case AttackerDamageHandler attackerDamageHandler: + { + if (Player.TryGet(attackerDamageHandler.Attacker, out Player attacker) && attacker.CurrentItem?.Type == ItemType.MarshmallowItem) + return DamageType.Marshmallow; + return DamageType.Unknown; + } } return DamageType.Unknown; diff --git a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs index c44a32362d..088438e085 100644 --- a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs +++ b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs @@ -101,6 +101,9 @@ public static class EffectTypeExtension { EffectType.TraumatizedByEvil, typeof(TraumatizedByEvil) }, { EffectType.WhiteCandy, typeof(WhiteCandy) }, { EffectType.Scp1509Resurrected, typeof(Scp1509Resurrected) }, + { EffectType.FocusedVision, typeof(FocusedVision) }, + { EffectType.AnomalousRegeneration, typeof(AnomalousRegeneration) }, + { EffectType.AnomalousTarget, typeof(AnomalousTarget) }, #pragma warning restore CS0618 }); diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs index 605e6466c0..3ba47fd9a8 100644 --- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs +++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs @@ -17,6 +17,7 @@ namespace Exiled.API.Extensions using AdminToys; using AudioPooling; + using Cassie; using CustomPlayerEffects; using Exiled.API.Enums; using Exiled.API.Features.Items; @@ -512,13 +513,12 @@ public static void ResyncKeycardPickup(CustomKeycardPickup customKeycard) /// Same on 's isSubtitles. public static void PlayCassieAnnouncement(this Player player, string words, bool makeHold = false, bool makeNoise = true, bool isSubtitles = false) { - foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) - { - if (controller != null) - { - SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), words, makeHold, makeNoise, isSubtitles); - } - } + CassieAnnouncement announcement = new(new CassieTtsPayload(words, isSubtitles, makeHold), 0, makeNoise ? 1 : 0); + + // processes makeNoise + announcement.OnStartedPlaying(); + + announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); } /// @@ -533,23 +533,12 @@ public static void PlayCassieAnnouncement(this Player player, string words, bool /// Same on 's isSubtitles. public static void MessageTranslated(this Player player, string words, string translation, string customSubtitles, bool makeHold = false, bool makeNoise = true, bool isSubtitles = true) { - StringBuilder announcement = StringBuilderPool.Pool.Get(); + CassieAnnouncement announcement = new(new CassieTtsPayload(words, customSubtitles, makeHold), 0, makeNoise ? 1 : 0); - string[] cassies = words.Split('\n'); - string[] translations = translation.Split('\n'); + // processes makeNoise + announcement.OnStartedPlaying(); - for (int i = 0; i < cassies.Length; i++) - announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); - - string message = StringBuilderPool.Pool.ToStringReturn(announcement); - - foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) - { - if (controller != null) - { - SendFakeTargetRpc(player, controller.netIdentity, typeof(RespawnEffectsController), nameof(RespawnEffectsController.RpcCassieAnnouncement), message, makeHold, makeNoise, isSubtitles, customSubtitles); - } - } + announcement.Payload.SendToHubsConditionally(hub => hub == player.ReferenceHub); } /// diff --git a/EXILED/Exiled.API/Extensions/RoleExtensions.cs b/EXILED/Exiled.API/Extensions/RoleExtensions.cs index 369910654a..db1a7c99a9 100644 --- a/EXILED/Exiled.API/Extensions/RoleExtensions.cs +++ b/EXILED/Exiled.API/Extensions/RoleExtensions.cs @@ -70,6 +70,7 @@ public static class RoleExtensions Team.FoundationForces or Team.Scientists => Side.Mtf, Team.ChaosInsurgency or Team.ClassD => Side.ChaosInsurgency, Team.OtherAlive => Side.Tutorial, + Team.Flamingos => Side.Flamingos, _ => Side.None, }; @@ -80,12 +81,13 @@ public static class RoleExtensions /// . public static Team GetTeam(this RoleTypeId roleType) => roleType switch { - RoleTypeId.ChaosConscript or RoleTypeId.ChaosMarauder or RoleTypeId.ChaosRepressor or RoleTypeId.ChaosRifleman => Team.ChaosInsurgency, + RoleTypeId.ChaosConscript or RoleTypeId.ChaosMarauder or RoleTypeId.ChaosRepressor or RoleTypeId.ChaosRifleman or RoleTypeId.ChaosFlamingo => Team.ChaosInsurgency, RoleTypeId.Scientist => Team.Scientists, RoleTypeId.ClassD => Team.ClassD, - RoleTypeId.Scp049 or RoleTypeId.Scp939 or RoleTypeId.Scp0492 or RoleTypeId.Scp079 or RoleTypeId.Scp096 or RoleTypeId.Scp106 or RoleTypeId.Scp173 or RoleTypeId.Scp3114 => Team.SCPs, - RoleTypeId.FacilityGuard or RoleTypeId.NtfCaptain or RoleTypeId.NtfPrivate or RoleTypeId.NtfSergeant or RoleTypeId.NtfSpecialist => Team.FoundationForces, + RoleTypeId.Scp049 or RoleTypeId.Scp939 or RoleTypeId.Scp0492 or RoleTypeId.Scp079 or RoleTypeId.Scp096 or RoleTypeId.Scp106 or RoleTypeId.Scp173 or RoleTypeId.Scp3114 or RoleTypeId.ZombieFlamingo=> Team.SCPs, + RoleTypeId.FacilityGuard or RoleTypeId.NtfCaptain or RoleTypeId.NtfPrivate or RoleTypeId.NtfSergeant or RoleTypeId.NtfSpecialist or RoleTypeId.NtfFlamingo => Team.FoundationForces, RoleTypeId.Tutorial => Team.OtherAlive, + RoleTypeId.Flamingo or RoleTypeId.AlphaFlamingo => Team.Flamingos, _ => Team.Dead, }; @@ -131,6 +133,7 @@ public static bool TryGetRoleBase(this RoleTypeId roleType, out T roleBase) Team.ClassD or Team.ChaosInsurgency => LeadingTeam.ChaosInsurgency, Team.FoundationForces or Team.Scientists => LeadingTeam.FacilityForces, Team.SCPs => LeadingTeam.Anomalies, + Team.Flamingos => LeadingTeam.Flamingo, _ => LeadingTeam.Draw, }; diff --git a/EXILED/Exiled.API/Features/Camera.cs b/EXILED/Exiled.API/Features/Camera.cs index fca5cbbc73..fa17a77540 100644 --- a/EXILED/Exiled.API/Features/Camera.cs +++ b/EXILED/Exiled.API/Features/Camera.cs @@ -143,6 +143,11 @@ public class Camera : IWrapper, IWorldSpace ["GATE A ELEVATORS"] = CameraType.EzGateAElevators, ["GATE B INTERIOR"] = CameraType.EzGateBInterior, ["GATE B SIDE"] = CameraType.EzGateBSide, + ["GATE A STAIRWELL"] = CameraType.EzGateAStairwell, + ["GATE A UPPER"] = CameraType.EzGateAUpper, + ["LOADING BAY"] = CameraType.HczLoadingBay, + ["HCZ LOADING RAMP"] = CameraType.HczLoadingBayRamp, + ["STAIRWELL"] = CameraType.HczLoadingBayStairwell, // CustomCamera ["EZ ARM CAMERA TOY"] = CameraType.EzArmCameraToy, diff --git a/EXILED/Exiled.API/Features/Cassie.cs b/EXILED/Exiled.API/Features/Cassie.cs index 0730f9a5a9..475e68ad4e 100644 --- a/EXILED/Exiled.API/Features/Cassie.cs +++ b/EXILED/Exiled.API/Features/Cassie.cs @@ -7,19 +7,19 @@ namespace Exiled.API.Features { + using System; using System.Collections.Generic; using System.Linq; using System.Text; using Exiled.API.Features.Pools; - + using global::Cassie; + using global::Cassie.Interpreters; using MEC; - using PlayerRoles; - using PlayerStatsSystem; - using Respawning; + using Respawning.NamingRules; using CustomFirearmHandler = DamageHandlers.FirearmDamageHandler; using CustomHandlerBase = DamageHandlers.DamageHandlerBase; @@ -29,20 +29,15 @@ namespace Exiled.API.Features /// public static class Cassie { - /// - /// Gets the singleton. - /// - public static NineTailedFoxAnnouncer Announcer => NineTailedFoxAnnouncer.singleton; - /// /// Gets a value indicating whether C.A.S.S.I.E is currently announcing. Does not include decontamination or Alpha Warhead Messages. /// - public static bool IsSpeaking => Announcer.queue.Count != 0; + public static bool IsSpeaking => CassieAnnouncementDispatcher.AllAnnouncements.Count != 0; /// - /// Gets a of objects that C.A.S.S.I.E recognizes. + /// Gets a of objects that C.A.S.S.I.E recognizes. /// - public static IReadOnlyCollection VoiceLines => Announcer.voiceLines; + public static IReadOnlyCollection VoiceLines => CassieAnnouncementDispatcher.AllAnnouncements; /// /// Reproduce a non-glitched C.A.S.S.I.E message. @@ -52,7 +47,7 @@ public static class Cassie /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void Message(string message, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles); + new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); /// /// Reproduce a non-glitched C.A.S.S.I.E message with a possibility to custom the subtitles. @@ -64,14 +59,7 @@ public static void Message(string message, bool isHeld = false, bool isNoisy = t /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void MessageTranslated(string message, string translation, bool isHeld = false, bool isNoisy = true, bool isSubtitles = true) { - StringBuilder announcement = StringBuilderPool.Pool.Get(); - string[] cassies = message.Split('\n'); - string[] translations = translation.Split('\n'); - for (int i = 0; i < cassies.Length; i++) - announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} "); - - RespawnEffectsController.PlayCassieAnnouncement(announcement.ToString(), isHeld, isNoisy, isSubtitles); - StringBuilderPool.Pool.Return(announcement); + new CassieAnnouncement(new CassieTtsPayload(message, translation, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue(); } /// @@ -81,7 +69,7 @@ public static void MessageTranslated(string message, string translation, bool is /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void GlitchyMessage(string message, float glitchChance, float jamChance) => - Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance); + new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue(); /// /// Reproduce a non-glitched C.A.S.S.I.E message after a certain amount of seconds. @@ -92,7 +80,7 @@ public static void GlitchyMessage(string message, float glitchChance, float jamC /// Indicates whether C.A.S.S.I.E has to make noises during the message. /// Indicates whether C.A.S.S.I.E has to make subtitles. public static void DelayedMessage(string message, float delay, bool isHeld = false, bool isNoisy = true, bool isSubtitles = false) => - Timing.CallDelayed(delay, () => RespawnEffectsController.PlayCassieAnnouncement(message, isHeld, isNoisy, isSubtitles)); + Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue()); /// /// Reproduce a glitchy C.A.S.S.I.E announcement after a certain period of seconds. @@ -102,17 +90,53 @@ public static void DelayedMessage(string message, float delay, bool isHeld = fal /// The chance of placing a glitch between each word. /// The chance of jamming each word. public static void DelayedGlitchyMessage(string message, float delay, float glitchChance, float jamChance) => - Timing.CallDelayed(delay, () => Announcer.ServerOnlyAddGlitchyPhrase(message, glitchChance, jamChance)); + Timing.CallDelayed(delay, () => new CassieAnnouncement(new CassieTtsPayload(CassieGlitchifier.Glitchify(message, glitchChance, jamChance), true, true), 0f, 0f).AddToQueue()); + + /// + /// Calculates the duration of a C.A.S.S.I.E message. + /// + /// The message, which duration will be calculated. + /// An obsolete parameter. + /// Another obsolete parameter. + /// Duration (in seconds) of specified message. + [Obsolete("Please use CalculateDuration(string)", true)] + public static float CalculateDuration(string message, bool obsolete1, float obsolete2) => CalculateDuration(message); /// /// Calculates the duration of a C.A.S.S.I.E message. /// /// The message, which duration will be calculated. - /// Determines if a number won't be converted to its full pronunciation. - /// The speed of the message. /// Duration (in seconds) of specified message. - public static float CalculateDuration(string message, bool rawNumber = false, float speed = 1f) - => Announcer.CalculateDuration(message, rawNumber, speed); + public static float CalculateDuration(string message) + { + if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) + { + return 0; + } + + float value = 0; + string[] lines = message.Split(' ', StringSplitOptions.RemoveEmptyEntries); + + CassiePlaybackModifiers modifiers = new(); + StringBuilder builder = StringBuilderPool.Pool.Get(); + + for (int i = 0; i < lines.Length; i++) + { + foreach (CassieInterpreter interpreter in CassieTtsAnnouncer.Interpreters) + { + bool halt; + foreach (CassieInterpreter.Result result in interpreter.GetResults(cassieLineDatabase, ref modifiers, lines[i], builder, out halt)) + { + value += (float)result.Modifiers.GetTimeUntilNextWord(result.Line); + } + + if (halt) + break; + } + } + + return value; + } /// /// Converts a into a Cassie-Readable CONTAINMENTUNIT. @@ -120,8 +144,16 @@ public static float CalculateDuration(string message, bool rawNumber = false, fl /// . /// Unit Name. /// Containment Unit text. - public static string ConvertTeam(Team team, string unitName) - => NineTailedFoxAnnouncer.ConvertTeam(team, unitName); + public static string ConvertTeam(Team team, string unitName) => team switch + { + Team.FoundationForces when NamingRulesManager.TryGetNamingRule(team, out UnitNamingRule unitNamingRule) => "CONTAINMENTUNIT " + unitNamingRule.TranslateToCassie(unitName), + Team.FoundationForces => "CONTAINMENTUNIT UNKNOWN", + Team.ChaosInsurgency => "BY CHAOSINSURGENCY", + Team.Scientists => "BY SCIENCE PERSONNEL", + Team.ClassD => "BY CLASSD PERSONNEL", + Team.Flamingos => "BY SCP 1 5 0 7", + _ => "UNKNOWN", + }; /// /// Converts a number into a Cassie-Readable String. @@ -129,7 +161,23 @@ public static string ConvertTeam(Team team, string unitName) /// Number to convert. /// A CASSIE-readable representing the number. public static string ConvertNumber(int num) - => NineTailedFoxAnnouncer.ConvertNumber(num); + { + if (!CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase)) + { + return string.Empty; + } + + NumberInterpreter numberInterpreter = (NumberInterpreter)CassieTtsAnnouncer.Interpreters.FirstOrDefault((CassieInterpreter x) => x is NumberInterpreter); + if (numberInterpreter == null) + { + return string.Empty; + } + + CassiePlaybackModifiers cassiePlaybackModifiers = default; + StringBuilder stringBuilder = new(); + numberInterpreter.GetResults(cassieLineDatabase, ref cassiePlaybackModifiers, num.ToString(), stringBuilder, out bool flag); + return stringBuilder.ToString(); + } /// /// Announce a SCP Termination. @@ -137,7 +185,7 @@ public static string ConvertNumber(int num) /// SCP to announce termination of. /// HitInformation. public static void ScpTermination(Player scp, DamageHandlerBase info) - => NineTailedFoxAnnouncer.AnnounceScpTermination(scp.ReferenceHub, info); + => CassieScpTerminationAnnouncement.AnnounceScpTermination(scp.ReferenceHub, info); /// /// Announces the termination of a custom SCP name. @@ -167,14 +215,14 @@ public static void CustomScpTermination(string scpName, CustomHandlerBase info) /// /// Clears the C.A.S.S.I.E queue. /// - public static void Clear() => RespawnEffectsController.ClearQueue(); + public static void Clear() => CassieAnnouncementDispatcher.ClearAll(); /// /// Gets a value indicating whether the given word is a valid C.A.S.S.I.E word. /// /// The word to check. /// if the word is valid; otherwise, . - public static bool IsValid(string word) => Announcer.voiceLines.Any(line => line.apiName.ToUpper() == word.ToUpper()); + public static bool IsValid(string word) => CassieTtsAnnouncer.TryGetDatabase(out CassieLineDatabase cassieLineDatabase) ? cassieLineDatabase.AllLines.Any(line => line.ApiName.ToUpper() == word.ToUpper()) : false; /// /// Gets a value indicating whether the given sentence is all valid C.A.S.S.I.E word. diff --git a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs index 67b464474f..fde6e9e00a 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs @@ -39,11 +39,17 @@ public CustomDamageHandler(Player target, BaseHandler baseHandler) if (Attacker is not null) { if (baseHandler is BaseScpDamageHandler) + { CustomBase = new ScpDamageHandler(target, baseHandler); - else if (Attacker.CurrentItem is not null && Attacker.CurrentItem.Type.IsWeapon() && baseHandler is BaseFirearmHandler) - CustomBase = new FirearmDamageHandler(Attacker.CurrentItem, target, baseHandler); + } else - CustomBase = new DamageHandler(target, Attacker); + { + Item item = Attacker.CurrentItem; + if (item is not null && item.Type.IsWeapon() && baseHandler is BaseFirearmHandler) + CustomBase = new FirearmDamageHandler(item, target, baseHandler); + else + CustomBase = new DamageHandler(target, Attacker); + } } else { diff --git a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs index ec59d5ee5a..248e89452b 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs @@ -271,6 +271,13 @@ protected DamageType GetDamageType(BaseHandler damageHandler = null) FirearmType.FRMG0 => DamageType.Frmg0, _ => DamageType.Firearm }; + + case PlayerStatsSystem.AttackerDamageHandler attackerDamageHandler: + { + if (Player.TryGet(attackerDamageHandler.Attacker, out Player attacker) && attacker.CurrentItem?.Type == ItemType.MarshmallowItem) + return DamageType.Marshmallow; + return DamageType.Unknown; + } } return DamageType.Unknown; diff --git a/EXILED/Exiled.API/Features/Doors/Door.cs b/EXILED/Exiled.API/Features/Doors/Door.cs index 19718900a7..a8163f207c 100644 --- a/EXILED/Exiled.API/Features/Doors/Door.cs +++ b/EXILED/Exiled.API/Features/Doors/Door.cs @@ -624,6 +624,7 @@ private DoorType GetDoorType() RoomType.HczEzCheckpointA => DoorType.CheckpointArmoryA, RoomType.HczEzCheckpointB => DoorType.CheckpointArmoryB, RoomType.EzGateA => DoorType.GateAArmory, + RoomType.HczLoadingBay => DoorType.HczLoadingBay, _ => DoorType.UnknownDoor, }, "Unsecured Pryable GateDoor" => Room?.Type switch diff --git a/EXILED/Exiled.API/Features/Effect.cs b/EXILED/Exiled.API/Features/Effect.cs index f901966917..426b68dcdc 100644 --- a/EXILED/Exiled.API/Features/Effect.cs +++ b/EXILED/Exiled.API/Features/Effect.cs @@ -35,7 +35,7 @@ public Effect(StatusEffectBase statusEffectBase) if (!statusEffectBase.TryGetEffectType(out EffectType effect)) Log.Error($"EffectType not found please report to Exiled BugReport : {statusEffectBase}"); Type = effect; - Duration = statusEffectBase.Duration; + Duration = statusEffectBase.TimeLeft; Intensity = statusEffectBase.Intensity; IsEnabled = statusEffectBase.IsEnabled; } diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs index 50a2538c64..8fb2688bb7 100644 --- a/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs @@ -11,9 +11,8 @@ namespace Exiled.API.Features.Items.FirearmModules using Exiled.API.Features.Items.FirearmModules.Barrel; using Exiled.API.Features.Items.FirearmModules.Primary; - using InventorySystem.Items.Firearms.Modules; - + using InventorySystem.Items.Firearms.Modules.Scp127; using UnityEngine; /// @@ -66,8 +65,12 @@ public static Magazine Get(IAmmoContainerModule module) PumpActionModule pump => new PumpBarrelMagazine(pump), IPrimaryAmmoContainerModule primary => primary switch { - MagazineModule magazine => new NormalMagazine(magazine), CylinderAmmoModule cylinder => new CylinderMagazine(cylinder), + MagazineModule magazine => magazine switch + { + Scp127MagazineModule scp127MagazineModule => new Scp127Magazine(scp127MagazineModule), + _ => new NormalMagazine(magazine) + }, _ => null, }, _ => null, diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs new file mode 100644 index 0000000000..c3226169ea --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Scp127Magazine.cs @@ -0,0 +1,80 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items.FirearmModules.Primary +{ + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Represents a normal magazine for SCP-127. + /// + public class Scp127Magazine : NormalMagazine + { + /// + /// Initializes a new instance of the class. + /// + /// + public Scp127Magazine(Scp127MagazineModule magazine) + : base(magazine) + { + MagazineModule = magazine; + } + + /// + public new Scp127MagazineModule MagazineModule { get; } + + /// + /// Gets or sets the kill bonus. + /// + public int KillBonus + { + get => MagazineModule.KillBonus; + set => MagazineModule.KillBonus = value; + } + + /// + /// Gets or sets the rank up bonus. + /// + public int RankUpBonus + { + get => MagazineModule.RankUpBonus; + set => MagazineModule.RankUpBonus = value; + } + + /// + /// Gets or sets all settings. + /// + public Scp127MagazineModule.RegenerationSettings[] RegenerationPerTier + { + get => MagazineModule._regenerationPerTier; + set => MagazineModule._regenerationPerTier = value; + } + + /// + /// Gets the current setting. + /// + public Scp127MagazineModule.RegenerationSettings ActiveSetting => MagazineModule.ActiveSettings; + + /// + /// Gets or sets a pause in bullets regeneration process. + /// + public float RemainingRegenPause + { + get => MagazineModule._remainingRegenPause; + set => MagazineModule._remainingRegenPause = value; + } + + /// + /// Gets or sets the amount of bullets that should be regenerated. + /// + public float RegenProgress + { + get => MagazineModule._regenProgress; + set => MagazineModule._regenProgress = value; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs index f9d8a74a0d..89bb189c42 100644 --- a/EXILED/Exiled.API/Features/Items/Item.cs +++ b/EXILED/Exiled.API/Features/Items/Item.cs @@ -22,6 +22,7 @@ namespace Exiled.API.Features.Items using InventorySystem.Items.Firearms.Ammo; using InventorySystem.Items.Jailbird; using InventorySystem.Items.Keycards; + using InventorySystem.Items.MarshmallowMan; using InventorySystem.Items.MicroHID; using InventorySystem.Items.Pickups; using InventorySystem.Items.Radio; @@ -218,7 +219,11 @@ public static Item Get(ItemBase itemBase) return itemBase switch { - InventorySystem.Items.Firearms.Firearm firearm => new Firearm(firearm), + InventorySystem.Items.Firearms.Firearm firearm => firearm.ItemTypeId switch + { + ItemType.GunSCP127 => new Scp127(firearm), + _ => new Firearm(firearm), + }, KeycardItem keycard => keycard switch { ChaosKeycardItem chaosKeycardItem => new ChaosKeycard(chaosKeycardItem), @@ -256,6 +261,7 @@ public static Item Get(ItemBase itemBase) _ => new Throwable(throwable), }, Scp1509Item scp1509 => new Scp1509(scp1509), + MarshmallowItem marshmallow => new Marshmallow(marshmallow), _ => new(itemBase), }; } @@ -318,7 +324,11 @@ public static T Get(ushort serial) /// The created. This can be cast as a subclass. public static Item Create(ItemType type, Player owner = null) => type.GetTemplate() switch { - InventorySystem.Items.Firearms.Firearm => new Firearm(type), + InventorySystem.Items.Firearms.Firearm => type switch + { + ItemType.GunSCP127 => new Scp127(), + _ => new Firearm(type), + }, KeycardItem keycard => keycard switch { ChaosKeycardItem => new ChaosKeycard(type), @@ -356,6 +366,7 @@ public static T Get(ushort serial) _ => new Throwable(type, owner), }, Scp1509Item => new Scp1509(), + MarshmallowItem => new Marshmallow(type, owner), _ => new(type), }; diff --git a/EXILED/Exiled.API/Features/Items/Jailbird.cs b/EXILED/Exiled.API/Features/Items/Jailbird.cs index b68a3473c2..4cc9a59c86 100644 --- a/EXILED/Exiled.API/Features/Items/Jailbird.cs +++ b/EXILED/Exiled.API/Features/Items/Jailbird.cs @@ -52,8 +52,8 @@ internal Jailbird() /// public float MeleeDamage { - get => Base._hitreg._damageMelee; - set => Base._hitreg._damageMelee = value; + get => Base.MeleeDamage; + set => Base.MeleeDamage = value; } /// @@ -61,8 +61,8 @@ public float MeleeDamage /// public float ChargeDamage { - get => Base._hitreg._damageCharge; - set => Base._hitreg._damageCharge = value; + get => Base._chargeDamage; + set => Base._chargeDamage = value; } /// @@ -70,8 +70,8 @@ public float ChargeDamage /// public float FlashDuration { - get => Base._hitreg._flashedDuration; - set => Base._hitreg._flashedDuration = value; + get => Base._flashedDuration; + set => Base._flashedDuration = value; } /// @@ -79,17 +79,17 @@ public float FlashDuration /// public float ConcussionDuration { - get => Base._hitreg._concussionDuration; - set => Base._hitreg._concussionDuration = value; + get => Base._concussionDuration; + set => Base._concussionDuration = value; } /// - /// Gets or sets the radius of the Jailbird's hit register. + /// Gets or sets the radius of the Jailbird's hit radius. /// public float Radius { - get => Base._hitreg._hitregRadius; - set => Base._hitreg._hitregRadius = value; + get => Base._hitregRadius; + set => Base._hitregRadius = value; } /// @@ -97,10 +97,10 @@ public float Radius /// public float TotalDamageDealt { - get => Base._hitreg.TotalMeleeDamageDealt; + get => Base.TotalMeleeDamageDealt; set { - Base._hitreg.TotalMeleeDamageDealt = value; + Base.TotalMeleeDamageDealt = value; Base._deterioration.RecheckUsage(); } } diff --git a/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs b/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs index 8d8bdad39d..bab50d19ce 100644 --- a/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs +++ b/EXILED/Exiled.API/Features/Items/Keycards/ChaosKeycard.cs @@ -43,7 +43,8 @@ internal ChaosKeycard(ItemType type) /// /// Gets the this encapsulates. /// - public SnakeEngine SnakeEngine => Base._localEngine; + /// Can be null, but shouldn't be during usage. + public SnakeEngine SnakeEngine => ChaosKeycardItem.SnakeSessions.TryGetValue(Serial, out SnakeEngine engine) ? engine : null; /// /// Returns the Keycard in a human readable format. diff --git a/EXILED/Exiled.API/Features/Items/Marshmallow.cs b/EXILED/Exiled.API/Features/Items/Marshmallow.cs new file mode 100644 index 0000000000..349fe342fb --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/Marshmallow.cs @@ -0,0 +1,102 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items +{ + using CustomPlayerEffects; + using Exiled.API.Interfaces; + using InventorySystem.Items.MarshmallowMan; + using PlayerStatsSystem; + using UnityEngine; + + /// + /// A wrapper class for . + /// + public class Marshmallow : Item, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// The base class. + public Marshmallow(MarshmallowItem itemBase) + : base(itemBase) + { + Base = itemBase; + } + + /// + /// Initializes a new instance of the class. + /// + /// The of the marshmallow item. + /// The owner of the marshmallow item. Leave for no owner. + internal Marshmallow(ItemType type, Player owner = null) + : base((MarshmallowItem)(owner ?? Server.Host).Inventory.CreateItemInstance(new(type, 0), false)) + { + } + + /// + /// Gets the that this class is encapsulating. + /// + public new MarshmallowItem Base { get; } + + /// + /// Gets a value indicating whether this marshmallow man is evil. + /// + /// See in regards to making a marshmallow evil. + public bool Evil => Base.EvilMode; + + /// + /// Gets or sets the of the marshmallow man that would be used if he was evil. + /// + public AhpStat.AhpProcess EvilAhpProcess + { + get => Base.EvilAHPProcess; + set + { + if (Evil && value is null) + return; + + Base.EvilAHPProcess = value; + } + } + + /// + /// Cackles for the owner even if they are not evil. + /// + /// How long until the player can cackle again (negative values do not affect current cooldown). + /// How long players near the marshmallow man get effected by . + public void Cackle(double cooldown = -1, float duration = 5) + { + if (cooldown >= 0) + Base._cackleCooldown.Trigger(cooldown); + + Base.ServerSendPublicRpc(writer => + { + writer.WriteByte(4); + Base._cackleCooldown.WriteCooldown(writer); + }); + + foreach (Player player in Player.List) + { + if (Vector3.Distance(player.Position, Owner.Position) <= 5F && player.CurrentItem is not Marshmallow { Evil: true }) + player.EnableEffect(duration); + } + } + + /// + /// Makes the owner of this marshmallow evil. You CANNOT undo this without resetting the player. + /// + /// The of the new evil player. + public void MakeEvil(AhpStat.AhpProcess evilProcess = null) + { + if (Evil) + return; + + Base.ReleaseEvil(evilProcess ?? EvilAhpProcess ?? Owner.GetModule().ServerAddProcess(450F, 450F, 0F, 1F, 0F, true)); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Items/Scp127.cs b/EXILED/Exiled.API/Features/Items/Scp127.cs new file mode 100644 index 0000000000..2c71fbe4bb --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/Scp127.cs @@ -0,0 +1,274 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items +{ + using System.Collections.Generic; + using System.Linq; + + using InventorySystem.Items.Firearms.Modules; + using InventorySystem.Items.Firearms.Modules.Scp127; + using UnityEngine; + + /// + /// Represents SCP-127. + /// + public class Scp127 : Firearm + { + #pragma warning disable SA1401 + /// + /// Custom amount of max HS. + /// + internal float? CustomHsMax; + #pragma warning restore SA1401 + + /// + /// Initializes a new instance of the class. + /// + /// + public Scp127(InventorySystem.Items.Firearms.Firearm itemBase) + : base(itemBase) + { + foreach (ModuleBase module in Base.Modules) + { + switch (module) + { + case Scp127HumeModule humeModule: + HumeModule = humeModule; + break; + case Scp127TierManagerModule tierManagerModule: + TierManagerModule = tierManagerModule; + break; + case Scp127VoiceLineManagerModule voiceLineManagerModule: + VoiceLineManagerModule = voiceLineManagerModule; + break; + } + } + } + + /// + /// Initializes a new instance of the class. + /// + internal Scp127() + : this((InventorySystem.Items.Firearms.Firearm)Server.Host.Inventory.CreateItemInstance(new(ItemType.GunSCP127, 0), false)) + { + } + + /// + /// Gets a collection of all active HS sessions. + /// + public static List ActiveHumeShieldSessions => Scp127HumeModule.ServerActiveSessions; + + /// + /// Gets the instance. + /// + public Scp127HumeModule HumeModule { get; } + + /// + /// Gets the instance. + /// + public Scp127TierManagerModule TierManagerModule { get; } + + /// + /// Gets the instance. + /// + public Scp127VoiceLineManagerModule VoiceLineManagerModule { get; } + + /// + /// Gets or sets the maximum amount of HS. + /// + /// If setter is used, after tier chance this value won't be edited automatically. + public float HsMax + { + get => CustomHsMax ?? HumeModule.HsMax; + set => CustomHsMax = value; + } + + /// + /// Gets or sets a shield regeneration rate. + /// + public float ShieldRegenRate + { + get => HumeModule.ShieldRegenRate; + set => HumeModule.ShieldRegenRate = value; + } + + /// + /// Gets or sets a shield decay time. + /// + public float ShieldDecayRate + { + get => HumeModule.ShieldDecayRate; + set => HumeModule.ShieldDecayRate = value; + } + + /// + /// Gets or sets a pause before HS starts regeneration after damage being taken. + /// + public float ShieldOnDamagePause + { + get => HumeModule.ShieldOnDamagePause; + set => HumeModule.ShieldOnDamagePause = value; + } + + /// + /// Gets or sets a delay before HS starts dropping after unequipment. + /// + public float UnequipDecayDelay + { + get => HumeModule.UnequipDecayDelay; + set => HumeModule.UnequipDecayDelay = value; + } + + /// + /// Gets or sets a HumeShield regeneration. + /// + public float HsRegeneration + { + get => HumeModule.HsRegeneration; + set => HumeModule.HsRegeneration = value; + } + + /// + /// Gets or sets an experience bonus for kill. + /// + public float KillBonus + { + get => TierManagerModule.KillBonus; + set => TierManagerModule.KillBonus = value; + } + + /// + /// Gets or sets an amount of passive experience increase. + /// + public float PassiveExpAmount + { + get => TierManagerModule.PassiveExpAmount; + set => TierManagerModule.PassiveExpAmount = value; + } + + /// + /// Gets or sets an interval of passive experience increase. + /// + public float PassiveExpInterval + { + get => TierManagerModule.PassiveExpInterval; + set => TierManagerModule.PassiveExpInterval = value; + } + + /// + /// Gets or sets a collection of all tier thresholds. + /// + public Scp127TierManagerModule.TierThreshold[] TierThresholds + { + get => TierManagerModule.Thresholds; + set => TierManagerModule.Thresholds = value; + } + + /// + /// Gets or sets current tier. + /// + public Scp127Tier CurrentTier + { + get => TierManagerModule.CurTier; + set => TierManagerModule.CurTier = value; + } + + /// + /// Gets or sets the current experience amount. + /// + public float Experience + { + get => TierManagerModule.ServerExp; + set => TierManagerModule.ServerExp = value; + } + + /// + /// Gets the instance record. + /// + public Scp127TierManagerModule.InstanceRecord InstanceRecord => Scp127TierManagerModule.GetRecord(Serial); + + /// + /// Gets the Owner stats. + /// + public Scp127TierManagerModule.OwnerStats OwnerStats => Scp127TierManagerModule.GetStats(Base); + + /// + /// Gets or sets all Voice Triggers. + /// + public Scp127VoiceTriggerBase[] VoiceTriggers + { + get => VoiceLineManagerModule._foundTriggers; + set => VoiceLineManagerModule._foundTriggers = value; + } + + /// + /// Gets a collection of players that are friends with this SCP-127. + /// + public IEnumerable Friends + { + get + { + if (!Scp127VoiceLineManagerModule.FriendshipMemory.TryGetValue(Serial, out HashSet uintSet)) + return null; + + return uintSet.Select(Player.Get); + } + } + + /// + /// Increases experience. + /// + /// Amount to add. + public void IncreaseExperience(float amount) => TierManagerModule.ServerIncreaseExp(Base, amount); + + /// + /// Sets owner stats. + /// + /// New experience amount. + public void SetOwnerStats(float exp) => TierManagerModule.ServerSetStats(exp); + + /// + /// Sends tier stats. + /// + /// New tier. + /// New progress. + public void SendTierStats(Scp127Tier tier, byte progress) => TierManagerModule.ServerSendStats(Serial, Owner.ReferenceHub, tier, progress); + + /// + /// Tries to play voice line. + /// + /// Voice line to play. + /// Priority of the play. + /// true if voice line has been played successfully. Otherwise, false. + public bool TryPlayVoiceLine(Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority priority = Scp127VoiceTriggerBase.VoiceLinePriority.Normal) + { + if (!VoiceLineManagerModule.TryFindVoiceLine(voiceLine, out Scp127VoiceTriggerBase triggerBase, out AudioClip audioClip)) + return false; + + VoiceLineManagerModule.ServerSendVoiceLine(triggerBase, null, audioClip, (byte)priority); + return true; + } + + /// + /// Checks if this instance of SCP-127 and have friendship. + /// + /// Target to check. + /// true if this instance of SCP-127 and have friendship. Otherwise, false. + public bool HasFriendship(Player player) => Scp127VoiceLineManagerModule.HasFriendship(Serial, player.ReferenceHub); + + /// + /// Adds player as a friend. + /// + /// Target to be added. + public void AddFriend(Player player) + { + HashSet uints = Scp127VoiceLineManagerModule.FriendshipMemory.GetOrAddNew(Serial); + uints.Add(player.NetId); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Lift.cs b/EXILED/Exiled.API/Features/Lift.cs index 469a33bd22..d191cd6764 100644 --- a/EXILED/Exiled.API/Features/Lift.cs +++ b/EXILED/Exiled.API/Features/Lift.cs @@ -47,6 +47,7 @@ public class Lift : IWrapper, IWorldSpace internal Lift(ElevatorChamber elevator) { Base = elevator; + ElevatorAutoReturn = elevator.GetComponent(); ElevatorChamberToLift.Add(elevator, this); internalDoorsList.AddRange(Elevator.AllElevatorDoors[Group]); @@ -73,6 +74,12 @@ internal Lift(ElevatorChamber elevator) /// public ElevatorChamber Base { get; } + /// + /// Gets the base . + /// + /// Would be null for any elevator that do not used . + public ElevatorAutoReturn ElevatorAutoReturn { get; } + /// /// Gets a value of the internal doors list. /// diff --git a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs index 0494d2e966..eaaf77cb7a 100644 --- a/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/JailbirdPickup.cs @@ -123,11 +123,11 @@ protected override void InitializeProperties(ItemBase itemBase) base.InitializeProperties(itemBase); if (itemBase is JailbirdItem jailbirdItem) { - MeleeDamage = jailbirdItem._hitreg._damageMelee; - ChargeDamage = jailbirdItem._hitreg._damageCharge; - FlashDuration = jailbirdItem._hitreg._flashedDuration; - ConcussionDuration = jailbirdItem._hitreg._concussionDuration; - Radius = jailbirdItem._hitreg._hitregRadius; + MeleeDamage = jailbirdItem.MeleeDamage; + ChargeDamage = jailbirdItem._chargeDamage; + FlashDuration = jailbirdItem._flashedDuration; + ConcussionDuration = jailbirdItem._concussionDuration; + Radius = Radius; } } } diff --git a/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs b/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs index b11c1cb0e9..935bc636ca 100644 --- a/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/Scp1509Pickup.cs @@ -15,7 +15,7 @@ namespace Exiled.API.Features.Pickups using BaseScp1509 = InventorySystem.Items.Scp1509.Scp1509Pickup; /// - /// A wrapper class for a Radio pickup. + /// A wrapper class for a Scp1509 pickup. /// public class Scp1509Pickup : Pickup, IWrapper { diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index a61d640a84..956fcf7f23 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -648,7 +648,7 @@ public ScpSpawnPreferences.SpawnPreferences ScpPreferences /// /// Gets a value indicating whether the player is reloading a weapon. /// - public bool IsReloading => CurrentItem is Firearm firearm && !firearm.IsReloading; + public bool IsReloading => CurrentItem is Firearm firearm && firearm.IsReloading; /// /// Gets a value indicating whether the player is aiming with a weapon. @@ -1982,10 +1982,24 @@ public void SetRank(string name, UserGroup group) ReferenceHub.serverRoles.SetGroup(group, false, false); } - if (ServerStatic.PermissionsHandler.Members.ContainsKey(UserId)) + ServerStatic.PermissionsHandler.Members[UserId] = name; + } + + /// + /// If the rank(group) exists in the remote admin config, it will assign it to the player. + /// + /// The rank name to be set. + /// if the rank(group) was found and successfully assigned, otherwise. + public bool TrySetRank(string name) + { + if (ServerStatic.PermissionsHandler.Groups.TryGetValue(name, out UserGroup userGroup)) + { + ReferenceHub.serverRoles.SetGroup(userGroup, false, false); ServerStatic.PermissionsHandler.Members[UserId] = name; - else - ServerStatic.PermissionsHandler.Members.Add(UserId, name); + return true; + } + + return false; } /// @@ -2029,6 +2043,21 @@ public void Broadcast(Broadcast broadcast, bool shouldClearPrevious = false) Broadcast(broadcast.Duration, broadcast.Content, broadcast.Type, shouldClearPrevious); } + /// + /// Send an to the player. + /// + /// The to be broadcasted. + /// if Cassie failed to play it or it's play nothing, otherwise it's return the duration of the annoucement. + public float CassieAnnouncement(global::Cassie.CassieAnnouncement cassieAnnouncement) + { + global::Cassie.CassieAnnouncementDispatcher.CurrentAnnouncement.OnStartedPlaying(); + global::Cassie.CassieTtsPayload payload = cassieAnnouncement.Payload; + if (!global::Cassie.CassieTtsAnnouncer.TryPlay(payload, out float totalduration)) + return 0; + payload.SendToHubsConditionally(x => x == ReferenceHub); + return totalduration; + } + /// /// Drops an item from the player's inventory. /// @@ -2061,10 +2090,12 @@ public void DropItem(Item item, bool isThrown = false) /// Dropped item's . public Pickup DropHeldItem() { - if (CurrentItem is null) + Item item = CurrentItem; + + if (item is null) return null; - return DropItem(CurrentItem); + return DropItem(item); } /// @@ -3449,10 +3480,7 @@ public void SyncEffect(Effect effect) { if (effect.IsEnabled) { - EnableEffect(effect.Type, effect.Duration, effect.AddDurationIfActive); - - if (effect.Intensity > 0) - ChangeEffectIntensity(effect.Type, effect.Intensity, effect.Duration); + EnableEffect(effect.Type, effect.Intensity, effect.Duration, effect.AddDurationIfActive); } } @@ -3580,8 +3608,7 @@ public void ChangeEffectIntensity(byte intensity, float duration = 0) { if (ReferenceHub.playerEffectsController.TryGetEffect(out T statusEffect)) { - statusEffect.Intensity = intensity; - statusEffect.ServerChangeDuration(duration, true); + statusEffect.ServerSetState(intensity, duration, false); } } @@ -3595,8 +3622,7 @@ public void ChangeEffectIntensity(EffectType type, byte intensity, float duratio { if (TryGetEffect(type, out StatusEffectBase statusEffect)) { - statusEffect.Intensity = intensity; - statusEffect.ServerChangeDuration(duration, false); + statusEffect.ServerSetState(intensity, duration, false); } } diff --git a/EXILED/Exiled.API/Features/Recontainer.cs b/EXILED/Exiled.API/Features/Recontainer.cs index 17f59c97d5..dbc31a35bf 100644 --- a/EXILED/Exiled.API/Features/Recontainer.cs +++ b/EXILED/Exiled.API/Features/Recontainer.cs @@ -7,6 +7,7 @@ namespace Exiled.API.Features { + using System; using System.Collections.Generic; using System.Linq; @@ -33,7 +34,8 @@ public static class Recontainer /// /// Gets a value indicating whether the C.A.S.S.I.E is currently busy. /// - public static bool IsCassieBusy => Base.CassieBusy; + [Obsolete("Use Cassie.IsSpeaking instead")] + public static bool IsCassieBusy => Cassie.IsSpeaking; /// /// Gets a value about how many generator have been activated. @@ -61,11 +63,8 @@ public static bool IsContainmentZoneLocked /// /// Gets or sets the delay to wait before overcharging. /// - public static float OverchargeDelay - { - get => Base._activationDelay; - set => Base._activationDelay = value; - } + [Obsolete("Will be removed in Exiled 10, patch the Cassie079RecontainAnnouncement ctor if you need this functionality")] + public static float OverchargeDelay { get; set; } /// /// Gets or sets the lockdown duration. @@ -188,7 +187,7 @@ public static bool IsContainmentSequenceSuccessful /// /// The announcement to play. /// The glitchy multiplier. - public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, glitchyMultiplier); + public static void PlayAnnouncement(string announcement, float glitchyMultiplier) => Base.PlayAnnouncement(announcement, false, false, null); /// /// Begins the overcharge procedure. @@ -199,7 +198,6 @@ public static void BeginOvercharge(bool endOvercharge = true) Base.BeginOvercharge(); if (endOvercharge) { - Base._delayStopwatch.Stop(); Base._unlockStopwatch.Start(); } } @@ -228,7 +226,7 @@ public static void BeginOvercharge(bool endOvercharge = true) /// /// Begins the recontainment procedure. /// - public static void Recontain() => Base.Recontain(); + public static void Recontain() => Base.Recontain(false); /// /// Refreshes the activator. diff --git a/EXILED/Exiled.API/Features/Roles/FpcRole.cs b/EXILED/Exiled.API/Features/Roles/FpcRole.cs index 2b0d75cf00..9a1156833e 100644 --- a/EXILED/Exiled.API/Features/Roles/FpcRole.cs +++ b/EXILED/Exiled.API/Features/Roles/FpcRole.cs @@ -300,6 +300,30 @@ public BasicRagdoll Ragdoll /// public SpectatableModuleBase SpectatableModuleBase => FirstPersonController.SpectatorModule; + /// + /// Tries to get the of a specified bone. + /// + /// The bone to get the of. + /// + /// When this method returns, contains the of the specified bone, if found; + /// otherwise, null. + /// + /// true if the bone transform was found; otherwise, false. + public bool TryGetBoneTransform(HumanBodyBones bone, out Transform boneTransform) + { + boneTransform = null; + + if (Model is not AnimatedCharacterModel animatedModel) + return false; + + Animator animator = animatedModel.Animator; + if (animator == null || animator.avatar == null || !animator.avatar.isValid || !animator.avatar.isHuman) + return false; + + boneTransform = animator.GetBoneTransform(bone); + return boneTransform != null; + } + /// /// Resets the 's stamina. /// diff --git a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs index 1c015e2ff0..6283226eb4 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp049Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp049Role.cs @@ -271,8 +271,7 @@ public void Attack(Player player) else { cardiacArrest.SetAttacker(AttackAbility.Owner); - cardiacArrest.Intensity = 1; - cardiacArrest.ServerChangeDuration(AttackAbility._statusEffectDuration, false); + cardiacArrest.ServerSetState(1, AttackAbility._statusEffectDuration, false); } SenseAbility.OnServerHit(AttackAbility._target); diff --git a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs index a59e699ac9..6e78b6c662 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp096Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp096Role.cs @@ -16,6 +16,8 @@ namespace Exiled.API.Features.Roles using PlayerRoles.PlayableScps.Scp096; using PlayerRoles.Subroutines; + using UnityEngine; + using Scp096GameRole = PlayerRoles.PlayableScps.Scp096.Scp096Role; /// @@ -139,6 +141,20 @@ internal Scp096Role(Scp096GameRole baseRole) /// public bool AttackPossible => AttackAbility.AttackPossible; + /// + /// Gets the head transform of SCP-096's character model. + /// + public Transform HeadTransform + { + get + { + if (Model is not Scp096CharacterModel scp96AnimatedCharacterModel) + return null; + + return scp96AnimatedCharacterModel.Head; + } + } + /// /// Gets or sets the Charge Ability Cooldown. /// @@ -306,4 +322,4 @@ public void Charge(float cooldown = 1f) /// The Spawn Chance. public float GetSpawnChance(List alreadySpawned) => Base.GetSpawnChance(alreadySpawned); } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs b/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs index a4c9ba78cf..170bda116a 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp1507Role.cs @@ -20,7 +20,7 @@ namespace Exiled.API.Features.Roles /// /// Defines a role that represents SCP-1507. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class Scp1507Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp { /// diff --git a/EXILED/Exiled.API/Features/Room.cs b/EXILED/Exiled.API/Features/Room.cs index a81a24173f..846a76509c 100644 --- a/EXILED/Exiled.API/Features/Room.cs +++ b/EXILED/Exiled.API/Features/Room.cs @@ -506,6 +506,7 @@ private static RoomType FindType(GameObject gameObject) "HCZ_ChkpB" => RoomType.HczElevatorB, "HCZ_127" => RoomType.Hcz127, "HCZ_ServerRoom" => RoomType.HczServerRoom, + "HCZ_Intersection_Ramp" => RoomType.HczLoadingBay, "EZ_GateA" => RoomType.EzGateA, "EZ_GateB" => RoomType.EzGateB, "EZ_ThreeWay" => RoomType.EzTCross, diff --git a/EXILED/Exiled.API/Features/Scp559.cs b/EXILED/Exiled.API/Features/Scp559.cs index 08fc899047..d05702b351 100644 --- a/EXILED/Exiled.API/Features/Scp559.cs +++ b/EXILED/Exiled.API/Features/Scp559.cs @@ -18,7 +18,7 @@ namespace Exiled.API.Features /// /// Represents a cake. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class Scp559 : IWrapper, IPosition { /// @@ -50,20 +50,34 @@ public Scp559(Scp559Cake cakeBase) /// /// Gets a with spawnpoint in rooms. /// - public static Dictionary SpawnPositions => Scp559Cake.Spawnpoints; + public static Dictionary SpawnPositions { get; } = Scp559Spawnpoint.InstancesPerRoom.ToDictionary(kvp => kvp.Key.Name, kvp => + { + Transform roomTransform = kvp.Key.transform; + Transform spawnTransform = kvp.Value.transform; + + Vector3 localPos = roomTransform.InverseTransformPoint(spawnTransform.position); + + return new Vector4(localPos.x, localPos.y, localPos.z, spawnTransform.eulerAngles.y); + }); /// /// Gets the list of all available spawnpoints. /// - public static List AvailableSpawnpoints => Scp559Cake.PossiblePositions; + public static List AvailableSpawnpoints => Scp559Cake.PossibleSpawnpoints.Select(spawnpoint => + { + Transform t = spawnpoint.transform; + return new Vector4(t.position.x, t.position.y, t.position.z, t.eulerAngles.y); + }).ToList(); /// /// Gets or sets offset for spawning near pedestals. /// public static Vector3 PedestalOffset { - get => Scp559Cake.PedestalOffset; - set => Scp559Cake.PedestalOffset.Set(value.x, value.y, value.z); + get => new(0, -Scp559Spawnpoint.PedestalHeight, 0); + + [Obsolete("Setter no longer works")] + set { } } /// diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs index 96b8311fdf..825cfb3566 100644 --- a/EXILED/Exiled.API/Features/Server.cs +++ b/EXILED/Exiled.API/Features/Server.cs @@ -111,7 +111,27 @@ public static string Name /// /// Gets the actual ticks per second of the server. /// - public static double Tps => Math.Round(1f / Time.smoothDeltaTime); + public static double Tps + { + get + { + double delta = Time.deltaTime; + + if (delta <= 0) + return MaxTps; + + double tps = 1d / delta; + + tps = Math.Min(tps, MaxTps); + + return tps; + } + } + + /// + /// Gets the average ticks per second of the server. + /// + public static double SmoothTps => Math.Round(1f / Time.smoothDeltaTime); /// /// Gets or sets the max ticks per second of the server. diff --git a/EXILED/Exiled.API/Features/Waves/TimedWave.cs b/EXILED/Exiled.API/Features/Waves/TimedWave.cs index 8856727c58..6e9a5c55bf 100644 --- a/EXILED/Exiled.API/Features/Waves/TimedWave.cs +++ b/EXILED/Exiled.API/Features/Waves/TimedWave.cs @@ -193,13 +193,13 @@ public static List GetTimedWaves() /// Plays the announcement for this wave. /// /// Wave must implement . - public void PlayAnnouncement() => Announcement?.PlayAnnouncement(new()); + public void PlayAnnouncement() => Announcement?.PlayAnnouncement([], Base as IAnnouncedWave); /// /// Plays the announcement for this wave. /// /// Wave must implement . /// The list of Player to spawn. - public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList()); + public void PlayAnnouncement(IEnumerable players) => Announcement?.PlayAnnouncement(players.Select(x => x.ReferenceHub).ToList(), Base as IAnnouncedWave); } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Window.cs b/EXILED/Exiled.API/Features/Window.cs index e5a1624e0d..2d327ff0c4 100644 --- a/EXILED/Exiled.API/Features/Window.cs +++ b/EXILED/Exiled.API/Features/Window.cs @@ -231,6 +231,7 @@ public void DamageWindow(float amount, DamageHandlerBase handler) RoomType.HczEzCheckpointB => GlassType.HczEzCheckpointB, RoomType.EzGateA when Base.name[7] == '5' => GlassType.GateAArmory, RoomType.EzGateA => GlassType.GateAPit, + RoomType.HczLoadingBay => GlassType.HczLoadingBay, _ => GlassType.Unknown, }, "Window" => Room?.Type switch diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs index fa39569e0a..182f47155e 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs @@ -1013,15 +1013,6 @@ private void OnInternalOwnerHandcuffing(HandcuffingEventArgs ev) continue; OnOwnerHandcuffing(new OwnerHandcuffingEventArgs(item, ev)); - - if (!ev.IsAllowed) - continue; - - ev.Target.RemoveItem(item); - - TrackedSerials.Remove(item.Serial); - - Spawn(ev.Target, item, ev.Target); } } diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index f29e2d525c..afce01ccdf 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -790,6 +790,12 @@ public bool TryAddFriendlyFire(Dictionary ffRules, bool overw return true; } + /// + /// Returns the CustomRole in a human-readable format. + /// + /// A string containing CustomRole-related data. + public override string ToString() => $"{Name} ({Id})"; + /// /// Tries to register this role. /// diff --git a/EXILED/Exiled.CustomRoles/Commands/Get.cs b/EXILED/Exiled.CustomRoles/Commands/Get.cs new file mode 100644 index 0000000000..7d96d5f6b4 --- /dev/null +++ b/EXILED/Exiled.CustomRoles/Commands/Get.cs @@ -0,0 +1,123 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.CustomRoles.Commands +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using System.Text; + + using CommandSystem; + using Exiled.API.Extensions; + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.CustomRoles.API; + using Exiled.CustomRoles.API.Features; + using Exiled.Permissions.Extensions; + using HarmonyLib; + + /// + /// The command to get specified player(s) current custom roles. + /// + internal sealed class Get : ICommand + { + private Get() + { + } + + /// + /// Gets the command instance. + /// + public static Get Instance { get; } = new(); + + /// + public string Command => "get"; + + /// + public string[] Aliases { get; } = Array.Empty(); + + /// + public string Description => "Gets the specified player(s)' current custom role(s)."; + + /// + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + if (!sender.CheckPermission("customroles.get")) + { + response = "Permission Denied, required: customroles.get"; + return false; + } + + List players = ListPool.Pool.Get(); + + if (arguments.Count > 0) + { + string identifier = string.Join(" ", arguments); + + switch (identifier.ToLower()) + { + case "*": + case "all": + players.AddRange(Player.List); + break; + default: + players.AddRange(Player.GetProcessedData(arguments)); + break; + } + + if (players.IsEmpty()) + { + if (arguments.Count > 0 || !Player.TryGet(sender, out Player player)) + { + response = $"Player not found: {identifier}"; + return false; + } + + players.Add(player); + } + } + else + { + response = "get "; + return false; + } + + StringBuilder builder = StringBuilderPool.Pool.Get(); + + builder.AppendLine(); + builder.AppendLine("====================== Custom Roles ======================"); + + foreach (Player target in players) + { + ReadOnlyCollection roles = target.GetCustomRoles(); + builder.Append((target.DisplayNickname + (target.HasCustomName ? $" ({target.Nickname})" : string.Empty)).PadRight(30 + (target.HasCustomName ? 23 : 0))); + builder.Append(" "); + builder.Append($"({target.Id})".PadRight(5)); + if (roles.IsEmpty()) + { + builder.AppendLine(" | No Custom Role"); + } + else + { + // builder.Append($" | [{string.Join(", ", roles.Select(role => $"{role}"))}]"); + builder.Append(" | ["); + builder.Append(string.Join(", ", roles.Select(role => $"{role}"))); + builder.AppendLine("]"); + } + } + + builder.AppendLine("=========================================================="); + + ListPool.Pool.Return(players); + + response = StringBuilderPool.Pool.ToStringReturn(builder); + return true; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.CustomRoles/Commands/Give.cs b/EXILED/Exiled.CustomRoles/Commands/Give.cs index 2f74b46498..9666bff990 100644 --- a/EXILED/Exiled.CustomRoles/Commands/Give.cs +++ b/EXILED/Exiled.CustomRoles/Commands/Give.cs @@ -83,7 +83,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s string identifier = string.Join(" ", arguments.Skip(1)); - switch (identifier) + switch (identifier.ToLower()) { case "*": case "all": diff --git a/EXILED/Exiled.CustomRoles/Commands/Parent.cs b/EXILED/Exiled.CustomRoles/Commands/Parent.cs index f64facabec..fd42b5e497 100644 --- a/EXILED/Exiled.CustomRoles/Commands/Parent.cs +++ b/EXILED/Exiled.CustomRoles/Commands/Parent.cs @@ -41,12 +41,13 @@ public override void LoadGeneratedCommands() RegisterCommand(Give.Instance); RegisterCommand(Info.Instance); RegisterCommand(List.List.Instance); + RegisterCommand(Get.Instance); } /// protected override bool ExecuteParent(ArraySegment arguments, ICommandSender sender, out string response) { - response = "Invalid subcommand! Available: give, info, list"; + response = "Invalid subcommand! Available: give, info, list, get"; return false; } } diff --git a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj index 78b2030580..cd1a8b4769 100644 --- a/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj +++ b/EXILED/Exiled.CustomRoles/Exiled.CustomRoles.csproj @@ -49,4 +49,4 @@ if [[ ! -z "$EXILED_DEV_REFERENCES" ]]; then cp "$(OutputPath)$(AssemblyName).dll" "$EXILED_DEV_REFERENCES/Plugins/"; fi - + \ No newline at end of file diff --git a/EXILED/Exiled.Events/Commands/TpsCommand.cs b/EXILED/Exiled.Events/Commands/TpsCommand.cs index 722de3b61e..14c0def05e 100644 --- a/EXILED/Exiled.Events/Commands/TpsCommand.cs +++ b/EXILED/Exiled.Events/Commands/TpsCommand.cs @@ -15,7 +15,6 @@ namespace Exiled.Events.Commands /// /// Command for showing current server TPS. /// - [CommandHandler(typeof(RemoteAdminCommandHandler))] [CommandHandler(typeof(GameConsoleCommandHandler))] public class TpsCommand : ICommand { @@ -31,7 +30,7 @@ public class TpsCommand : ICommand /// public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) { - double diff = Server.Tps / Server.MaxTps; + double diff = Server.SmoothTps / Server.MaxTps; string color = diff switch { > 0.9 => "green", @@ -39,7 +38,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s _ => "red" }; - response = $"{Server.Tps}/{Server.MaxTps}"; + response = $"{Server.SmoothTps}/{Server.MaxTps}"; return true; } } diff --git a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs index a8b986c171..abd2f4877f 100644 --- a/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Cassie/SendingCassieMessageEventArgs.cs @@ -7,39 +7,70 @@ namespace Exiled.Events.EventArgs.Cassie { + using System; + using System.Text; + + using Exiled.API.Features.Pools; + using global::Cassie; using Interfaces; + using Subtitles; /// /// Contains all the information after sending a C.A.S.S.I.E. message. /// public class SendingCassieMessageEventArgs : IDeniableEvent { + private readonly CassieAnnouncement announcement; + private readonly CassieTtsPayload payload; + + private string customSubtitles; + private float glitchScale; + /// /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - /// - /// - /// + /// The announcement to populate all properties from. + /// + /// /// - /// - /// - /// - /// - /// - /// - /// Indicates whether the event can be executed. - public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise, bool customAnnouncement, string customSubtitles, bool isAllowed = true) + public SendingCassieMessageEventArgs(CassieAnnouncement annc, bool isAllowed = true) { - Words = words; - CustomSubtitles = customSubtitles; - MakeHold = makeHold; - MakeNoise = makeNoise; - IsCustomAnnouncement = customAnnouncement; + announcement = annc; + payload = annc.Payload; + + Words = payload.Content; + switch (payload.SubtitleSource) + { + case CassieTtsPayload.SubtitleMode.None: + case CassieTtsPayload.SubtitleMode.Automatic: + CustomSubtitles = string.Empty; + break; + case CassieTtsPayload.SubtitleMode.Custom: + CustomSubtitles = payload._customSubtitle; + break; + case CassieTtsPayload.SubtitleMode.FromTranslation: + StringBuilder builder = StringBuilderPool.Pool.Get(); + SubtitleController controller = SubtitleController.Singleton; + + foreach (SubtitlePart part in payload._subtitleMessage.SubtitleParts) + { + Subtitle subtitle = controller.Subtitles[part.Subtitle]; + builder.Append(controller.GetTranslation(subtitle)); + } + + CustomSubtitles = StringBuilderPool.Pool.ToStringReturn(builder); + + break; + default: + CustomSubtitles = string.Empty; + break; + } + + MakeHold = payload.PlayBackground; + GlitchScale = annc.GlitchScale; + MakeNoise = annc.GlitchScale is not 0; + SubtitleSource = payload.SubtitleSource; + IsAllowed = isAllowed; } @@ -51,13 +82,38 @@ public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise /// /// Gets or sets the message subtitles. /// - public string CustomSubtitles { get; set; } + public string CustomSubtitles + { + get => customSubtitles; + set + { + if (customSubtitles != value) + SubtitleSource = CassieTtsPayload.SubtitleMode.Custom; + + customSubtitles = value; + } + } /// /// Gets or sets a value indicating whether the message should be held. /// public bool MakeHold { get; set; } + /// + /// Gets or sets a value controlling how glitchy this CASSIE message is. + /// + public float GlitchScale + { + get => glitchScale; + set + { + if (!MakeNoise && value is not 0) + MakeNoise = true; + + glitchScale = value; + } + } + /// /// Gets or sets a value indicating whether the message should make noise. /// @@ -69,8 +125,50 @@ public SendingCassieMessageEventArgs(string words, bool makeHold, bool makeNoise public bool IsAllowed { get; set; } /// - /// Gets or sets a value indicating whether the message can be sent. + /// Gets or sets a value indicating whether the event can be executed. /// + [Obsolete("Useless and will be removed in Exiled 10.")] public bool IsCustomAnnouncement { get; set; } + + /// + /// Gets or sets a value indicating where the subtitles for this message came from. + /// + public CassieTtsPayload.SubtitleMode SubtitleSource { get; set; } + + /// + /// Gets a consisting of all properties in this event. + /// + public CassieAnnouncement Announcement + { + get + { + CassieTtsPayload newPayload; + + // I love readonly fields :) + if (SubtitleSource is CassieTtsPayload.SubtitleMode.FromTranslation) + { + newPayload = new CassieTtsPayload(Words, MakeHold, payload._subtitleMessage.SubtitleParts); + } + else + { + if (SubtitleSource is CassieTtsPayload.SubtitleMode.Automatic) + newPayload = new CassieTtsPayload(Words, true, MakeHold); + else + newPayload = new CassieTtsPayload(Words, CustomSubtitles, MakeHold); + } + + return announcement switch + { + CassieScpTerminationAnnouncement => + + // this is disabled via patch b/c termination messages are not modifiable at the stage the SendCassieMessage patch is in. + throw new InvalidOperationException("SendCassieMessage was called for a SCP termination message!"), + + CassieWaveAnnouncement waveAnnc => new CassieWaveAnnouncement(waveAnnc.Wave, newPayload), + Cassie079RecontainAnnouncement recontainAnnc => new Cassie079RecontainAnnouncement(recontainAnnc._callback, false, newPayload), + _ => new CassieAnnouncement(newPayload, 0, GlitchScale / (API.Features.Warhead.IsDetonated ? 2F : 1F) * (MakeNoise ? 1F : 0F)), + }; + } + } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs new file mode 100644 index 0000000000..fdd41cef5b --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs @@ -0,0 +1,22 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Interfaces +{ + using Exiled.API.Features.Items; + + /// + /// Represents all events related to the marshmallow man. + /// + public interface IMarshmallowEvent : IItemEvent + { + /// + /// Gets the marshmallow item related to this event. + /// + public Marshmallow Marshmallow { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs new file mode 100644 index 0000000000..616ad8f3e5 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp127Event.cs @@ -0,0 +1,20 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Interfaces +{ + /// + /// Represents all events related to SCP-127. + /// + public interface IScp127Event : IItemEvent + { + /// + /// Gets the SCP-127 instance, related to this event. + /// + public API.Features.Items.Scp127 Scp127 { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs index 1d6dcf3add..acb2463878 100644 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs @@ -14,7 +14,7 @@ namespace Exiled.Events.EventArgs.Interfaces /// /// Event args used for all related events. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public interface IScp1507Event : IPlayerEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs index d8a5537257..fc62383340 100644 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp559Event.cs @@ -12,7 +12,7 @@ namespace Exiled.Events.EventArgs.Interfaces /// /// Defines the base contract for all related events. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public interface IScp559Event : IExiledEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs new file mode 100644 index 0000000000..8e491ee0b1 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Item +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.MarshmallowMan; + + /// + /// Contains all information before a marshmallow man punches. + /// + public class CacklingEventArgs : IMarshmallowEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The marshmallow item of the player cackling. + /// Whether the player is allowed to cackle. + public CacklingEventArgs(MarshmallowItem marshmallow, bool isAllowed = true) + { + Marshmallow = Item.Get(marshmallow); + Player = Marshmallow.Owner; + IsAllowed = isAllowed; + } + + /// + /// Gets the player cackling. + /// + public Player Player { get; } + + /// + public API.Features.Items.Item Item => Marshmallow; + + /// + /// Gets the marshmallow item of the player cackling. + /// + public Marshmallow Marshmallow { get; } + + /// + /// Gets or sets a value indicating whether the player is allowed to cackle. + /// + public bool IsAllowed { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs new file mode 100644 index 0000000000..d2d927d95a --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Item +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.MarshmallowMan; + + /// + /// Contains all information before a marshmallow man punches. + /// + public class PunchingEventArgs : IMarshmallowEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The marshmallow item of the player attacking. + /// Whether the player is allowed to punch. + public PunchingEventArgs(MarshmallowItem marshmallow, bool isAllowed = true) + { + Marshmallow = Item.Get(marshmallow); + Player = Marshmallow.Owner; + IsAllowed = isAllowed; + } + + /// + /// Gets the player punching. + /// + public Player Player { get; } + + /// + public Item Item => Marshmallow; + + /// + /// Gets the marshmallow item of the player punching. + /// + public Marshmallow Marshmallow { get; } + + /// + /// Gets or sets a value indicating whether the punch is allowed. + /// + public bool IsAllowed { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs index 4c43eb1df8..d8d38cc474 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingScpTerminationEventArgs.cs @@ -7,15 +7,13 @@ namespace Exiled.Events.EventArgs.Map { + using System; + using API.Features; using API.Features.DamageHandlers; using API.Features.Roles; - using Interfaces; - using CustomAttackerHandler = API.Features.DamageHandlers.AttackerDamageHandler; - using DamageHandlerBase = PlayerStatsSystem.DamageHandlerBase; - /// /// Contains all information before C.A.S.S.I.E announces an SCP termination. /// @@ -27,16 +25,14 @@ public class AnnouncingScpTerminationEventArgs : IAttackerEvent, IDeniableEvent /// /// /// - /// - /// + /// + /// /// - public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHandlerBase) + public AnnouncingScpTerminationEventArgs(Player scp, string terminationCause) { Player = scp; Role = scp.Role; - DamageHandler = new CustomDamageHandler(scp, damageHandlerBase); - Attacker = DamageHandler.BaseIs(out CustomAttackerHandler customAttackerHandler) ? customAttackerHandler.Attacker : null; - TerminationCause = damageHandlerBase.CassieDeathAnnouncement.Announcement; + TerminationCause = terminationCause; IsAllowed = true; } @@ -58,11 +54,13 @@ public AnnouncingScpTerminationEventArgs(Player scp, DamageHandlerBase damageHan /// /// Gets the player who killed the SCP. /// + [Obsolete("Attacker can no longer be acquired for this event. This will be readded in a different event.")] public Player Attacker { get; } /// /// Gets or sets the . /// + [Obsolete("DamageHandler can no longer be acquired for this event. This will be readded in a different event.")] public CustomDamageHandler DamageHandler { get; set; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs index 168a0f578e..038a3e16c4 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ReceivingEffectEventArgs.cs @@ -18,8 +18,6 @@ namespace Exiled.Events.EventArgs.Player /// public class ReceivingEffectEventArgs : IPlayerEvent, IDeniableEvent { - private byte intensity; - /// /// Initializes a new instance of the class. /// @@ -32,9 +30,9 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int { Player = player; Effect = effect; - this.intensity = intensity; + Intensity = intensity; CurrentIntensity = currentIntensity; - Duration = duration; + Duration = intensity is 0 ? 0 : duration; } /// @@ -53,20 +51,9 @@ public ReceivingEffectEventArgs(Player player, StatusEffectBase effect, byte int public float Duration { get; set; } = 0; /// - /// Gets or sets the value of the new intensity of the effect. Setting this to 0 is the same as setting IsAllowed to - /// . + /// Gets or sets the value of the new intensity of the effect. /// - public byte Intensity - { - get => intensity; - set - { - intensity = value; - - if (intensity == 0) - IsAllowed = false; - } - } + public byte Intensity { get; set; } /// /// Gets the value of the intensity of this effect on the player. diff --git a/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs new file mode 100644 index 0000000000..6dce01109c --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/Scp1576TransmissionEndedEventArgs.cs @@ -0,0 +1,41 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Player +{ + using API.Features; + using API.Features.Items; + using Interfaces; + using InventorySystem.Items.Usables.Scp1576; + + /// + /// Contains all information after a SCP-1576 transmission has ended. + /// + public class Scp1576TransmissionEndedEventArgs : IPlayerEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public Scp1576TransmissionEndedEventArgs(Player player, Scp1576Item scp1576Item) + { + Player = player; + Scp1576 = Item.Get(scp1576Item); + } + + /// + /// Gets the that the transmission ended for. + /// + public Player Player { get; } + + /// + /// Gets the instance. + /// + public Exiled.API.Features.Items.Scp1576 Scp1576 { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs index e25e9fd728..c6aeed7ffb 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/UsedItemEventArgs.cs @@ -28,10 +28,14 @@ public class UsedItemEventArgs : IPlayerEvent, IUsableEvent /// /// /// - public UsedItemEventArgs(ReferenceHub player, UsableItem item) + /// + /// + /// + public UsedItemEventArgs(ReferenceHub player, UsableItem item, bool causedByHolstering) { Player = Player.Get(player); - Usable = Item.Get(item) is Usable usable ? usable : null; + Usable = Item.Get(item) as Usable; + CausedByHolstering = causedByHolstering; } /// @@ -46,5 +50,11 @@ public UsedItemEventArgs(ReferenceHub player, UsableItem item) /// Gets the player who used the item. /// public Player Player { get; } + + /// + /// Gets a value indicating whether this event was triggered by a player switching items (true) or by waiting after using the item (false). + /// + /// Use this value if you wish to keep the bug where you could switch items quickly to skip this event. + public bool CausedByHolstering { get; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs new file mode 100644 index 0000000000..533ccbb5ce --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp127/GainedExperienceEventArgs.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp127 +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Contains all information before SCP-127 gains experience. + /// + public class GainedExperienceEventArgs : IScp127Event + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public GainedExperienceEventArgs(Scp127 scp127, float experience) + { + Scp127 = scp127; + Experience = experience; + Tier = Scp127.TierManagerModule.GetTierForExp(Experience + Scp127.Experience); + } + + /// + public Player Player => Scp127.Owner; + + /// + public Item Item => Scp127; + + /// + public Scp127 Scp127 { get; } + + /// + /// Gets the experience that SCP-127 has gained. + /// + public float Experience { get; } + + /// + /// Gets the tier. + /// + public Scp127Tier Tier { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs new file mode 100644 index 0000000000..6a1d7b738b --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp127/GainingExperienceEventArgs.cs @@ -0,0 +1,59 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp127 +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Contains all information before SCP-127 gains experience. + /// + public class GainingExperienceEventArgs : IScp127Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + public GainingExperienceEventArgs(Scp127 scp127, float experience, bool isAllowed = true) + { + Scp127 = scp127; + Experience = experience; + IsAllowed = isAllowed; + } + + /// + public Player Player => Scp127.Owner; + + /// + public Item Item => Scp127; + + /// + public Scp127 Scp127 { get; } + + /// + public bool IsAllowed { get; set; } + + /// + /// Gets or sets the gaining experience. + /// + public float Experience { get; set; } + + /// + /// Gets or sets the new tier. + /// + public Scp127Tier Tier + { + get => Scp127.TierManagerModule.GetTierForExp(Experience + Scp127.Experience); + set => Experience = Scp127.TierManagerModule.GetExpForTier(value) - Scp127.Experience; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs new file mode 100644 index 0000000000..10810403d5 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp127/TalkedEventArgs.cs @@ -0,0 +1,52 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp127 +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Contains all information after SCP-127 voice line is played. + /// + public class TalkedEventArgs : IScp127Event + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + public TalkedEventArgs(Scp127 scp127, Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority voiceLinePriority) + { + Scp127 = scp127; + VoiceLine = voiceLine; + Priority = voiceLinePriority; + } + + /// + public Player Player => Scp127.Owner; + + /// + public Item Item => Scp127; + + /// + public Scp127 Scp127 { get; } + + /// + /// Gets a voice line which is played. + /// + public Scp127VoiceLinesTranslation VoiceLine { get; } + + /// + /// Gets a priority for this play. + /// + public Scp127VoiceTriggerBase.VoiceLinePriority Priority { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs new file mode 100644 index 0000000000..b8934566a8 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp127/TalkingEventArgs.cs @@ -0,0 +1,57 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp127 +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Firearms.Modules.Scp127; + + /// + /// Contains all information before SCP-127 voice line is played. + /// + public class TalkingEventArgs : IScp127Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + public TalkingEventArgs(Scp127 scp127, Scp127VoiceLinesTranslation voiceLine, Scp127VoiceTriggerBase.VoiceLinePriority voiceLinePriority, bool isAllowed = true) + { + Scp127 = scp127; + VoiceLine = voiceLine; + Priority = voiceLinePriority; + IsAllowed = isAllowed; + } + + /// + public Player Player => Scp127.Owner; + + /// + public Item Item => Scp127; + + /// + public Scp127 Scp127 { get; } + + /// + public bool IsAllowed { get; set; } + + /// + /// Gets or sets a voice line which is played. + /// + public Scp127VoiceLinesTranslation VoiceLine { get; set; } + + /// + /// Gets or sets a priority for this play. + /// + public Scp127VoiceTriggerBase.VoiceLinePriority Priority { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs index c58330e252..c6ea947e55 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs @@ -18,7 +18,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 attacks door. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class AttackingDoorEventArgs : IScp1507Event, IDeniableEvent, IDoorEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs index ae5ebb8450..7ab56f98e2 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/ScreamingEventArgs.cs @@ -16,7 +16,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 screams. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class ScreamingEventArgs : IScp1507Event, IDeniableEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs index 376eba5abf..5cc50f9352 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/SpawningFlamingosEventArgs.cs @@ -19,7 +19,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before flamingos get spawned. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class SpawningFlamingosEventArgs : IDeniableEvent, IPlayerEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs index 0121d02d95..10b713052e 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp1507/UsingTapeEventArgs.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.EventArgs.Scp1507 /// /// Contains all information before SCP-1507 screams. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class UsingTapeEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent { /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs new file mode 100644 index 0000000000..d4935e6c92 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs @@ -0,0 +1,40 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp2536 +{ + using Christmas.Scp2536; + using Exiled.API.Features; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information after SCP-2536 chooses target for spawning. + /// + public class FoundPositionEventArgs : IPlayerEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public FoundPositionEventArgs(Player player, Scp2536Spawnpoint spawnpoint) + { + Player = player; + Spawnpoint = spawnpoint; + } + + /// + /// Gets the player near whom SCP-2536 will spawn. + /// + public Player Player { get; } + + /// + /// Gets or sets the spawn point where SCP will spawn. + /// + public Scp2536Spawnpoint Spawnpoint { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs index b8b99f9ac9..1a4a7408dc 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp559/InteractingScp559EventArgs.cs @@ -15,7 +15,7 @@ namespace Exiled.Events.EventArgs.Scp559 /// /// Contains all information before a player interacts with SCP-559. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class InteractingScp559EventArgs : IScp559Event, IDeniableEvent, IPlayerEvent { /// @@ -23,12 +23,11 @@ public class InteractingScp559EventArgs : IScp559Event, IDeniableEvent, IPlayerE /// /// /// - /// - public InteractingScp559EventArgs(Scp559 scp559, Player player, bool isAllowed = true) + public InteractingScp559EventArgs(Scp559 scp559, Player player) { Player = player; Scp559 = scp559; - IsAllowed = isAllowed; + IsAllowed = scp559.RemainingSlices > 0 && PlayerRoles.PlayerRolesUtils.IsHuman(player.Role.Type); } /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs index 6e3a81f06a..c83baddd2c 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp559/SpawningEventArgs.cs @@ -16,7 +16,7 @@ namespace Exiled.Events.EventArgs.Scp559 /// /// Contains all information before SCP-559 spawns. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public class SpawningEventArgs : IDeniableEvent, IScp559Event { /// diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index a1bdd040a2..adae6e21a8 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -21,6 +21,7 @@ namespace Exiled.Events using PlayerRoles.FirstPersonControl.NetworkMessages; using PlayerRoles.Ragdolls; using PlayerRoles.RoleAssign; + using Respawning; using UnityEngine.SceneManagement; using UserSettings.ServerSpecific; @@ -73,6 +74,7 @@ public override void OnEnabled() Handlers.Scp049.ActivatingSense += Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified += Handlers.Internal.Round.OnVerified; Handlers.Map.ChangedIntoGrenade += Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; + Handlers.Warhead.Detonated += Handlers.Internal.Round.OnWarheadDetonated; RoleAssigner.OnPlayersSpawned += Handlers.Server.OnAllPlayersSpawned; CharacterClassManager.OnRoundStarted += Handlers.Server.OnRoundStarted; @@ -95,6 +97,11 @@ public override void OnEnabled() FpcServerPositionDistributor.RoleSyncEvent += Handlers.Internal.Round.OnRoleSyncEvent; + LabApi.Events.Handlers.Scp127Events.Talking += Handlers.Scp127.OnTalking; + LabApi.Events.Handlers.Scp127Events.Talked += Handlers.Scp127.OnTalked; + LabApi.Events.Handlers.Scp127Events.GainingExperience += Handlers.Scp127.OnGainingExperience; + LabApi.Events.Handlers.Scp127Events.GainExperience += Handlers.Scp127.OnGainedExperience; + ServerConsole.ReloadServerName(); } @@ -135,6 +142,11 @@ public override void OnDisabled() LabApi.Events.Handlers.PlayerEvents.UnloadingWeapon -= Handlers.Player.OnUnloadingWeapon; FpcServerPositionDistributor.RoleSyncEvent -= Handlers.Internal.Round.OnRoleSyncEvent; + + LabApi.Events.Handlers.Scp127Events.Talking -= Handlers.Scp127.OnTalking; + LabApi.Events.Handlers.Scp127Events.Talked -= Handlers.Scp127.OnTalked; + LabApi.Events.Handlers.Scp127Events.GainingExperience -= Handlers.Scp127.OnGainingExperience; + LabApi.Events.Handlers.Scp127Events.GainExperience -= Handlers.Scp127.OnGainedExperience; } /// diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 4cedb7a21e..26ff90342a 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -29,6 +29,7 @@ namespace Exiled.Events.Handlers.Internal using InventorySystem.Items.Firearms.Attachments.Components; using InventorySystem.Items.Usables; using InventorySystem.Items.Usables.Scp244.Hypothermia; + using InventorySystem.Items.Usables.Scp330; using Mirror; using PlayerRoles; using PlayerRoles.FirstPersonControl; @@ -108,6 +109,9 @@ public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { if (ev.Role.IsDead() || !ev.Role.IsFpcRole()) ev.IsAllowed = false; + + if (ev.DamageHandlerBase is Exiled.Events.Patches.Fixes.FixMarshmallowManFF fixMarshamllowManFf) + ev.DamageHandlerBase = fixMarshamllowManFf.MarshmallowItem.NewDamageHandler; } /// @@ -136,7 +140,7 @@ public static void OnVerified(VerifiedEventArgs ev) } // Fix bug that player that Join do not receive information about other players Scale - foreach (Player player in Player.Enumerable) + foreach (Player player in ReferenceHub.AllHubs.Select(Player.Get)) { player.SetFakeScale(player.Scale, new List() { ev.Player }); @@ -178,6 +182,13 @@ public static RoleTypeId OnRoleSyncEvent(ReferenceHub viewerHub, ReferenceHub ow return actualRole; } + /// + public static void OnWarheadDetonated() + { + // fix for black candy + CandyBlack.Outcomes.RemoveAll(outcome => outcome is TeleportOutcome); + } + private static void GenerateAttachments() { foreach (FirearmType firearmType in EnumUtils.Values) diff --git a/EXILED/Exiled.Events/Handlers/Item.cs b/EXILED/Exiled.Events/Handlers/Item.cs index 9ac83aafd3..b1ca257f09 100644 --- a/EXILED/Exiled.Events/Handlers/Item.cs +++ b/EXILED/Exiled.Events/Handlers/Item.cs @@ -89,6 +89,16 @@ public static class Item /// public static Event JailbirdChangedWearState { get; set; } = new(); + /// + /// Invoked before a marshmallow man punches. + /// + public static Event Punching { get; set; } = new(); + + /// + /// Invoked before a marshmallow man cackles. + /// + public static Event Cackling { get; set; } = new(); + /// /// Called before the Jailbird's is changed. /// @@ -173,5 +183,17 @@ public static class Item /// /// The instance. public static void OnInspectedItem(InspectedItemEventArgs ev) => InspectedItem.InvokeSafely(ev); + + /// + /// Called before a marshmallow man punches. + /// + /// The instance. + public static void OnPunching(PunchingEventArgs ev) => Punching.InvokeSafely(ev); + + /// + /// Called before a marshmallow man cackles. + /// + /// The instance. + public static void OnCackling(CacklingEventArgs ev) => Cackling.InvokeSafely(ev); } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index 97e6137003..998b54f813 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -621,6 +621,11 @@ public class Player /// public static Event InteractingEmergencyButton { get; set; } = new(); + /// + /// Invoked after transmission has ended. + /// + public static Event Scp1576TransmissionEnded { get; set; } = new(); + /// /// Called before a player's emotion changed. /// @@ -1356,5 +1361,11 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item /// /// The instance. public static void OnInteractingEmergencyButton(InteractingEmergencyButtonEventArgs ev) => InteractingEmergencyButton.InvokeSafely(ev); + + /// + /// Called after a 1576 transmisiion has ended. + /// + /// The instance. + public static void OnScp1576TransmissionEnded(Scp1576TransmissionEndedEventArgs ev) => Scp1576TransmissionEnded.InvokeSafely(ev); } } diff --git a/EXILED/Exiled.Events/Handlers/Scp127.cs b/EXILED/Exiled.Events/Handlers/Scp127.cs new file mode 100644 index 0000000000..b3f86534d3 --- /dev/null +++ b/EXILED/Exiled.Events/Handlers/Scp127.cs @@ -0,0 +1,81 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Handlers +{ + using Exiled.Events.EventArgs.Scp127; + using Exiled.Events.Features; + using LabApi.Events.Arguments.Scp127Events; + +#pragma warning disable SA1623 + /// + /// SCP-127 event handlers. + /// + public static class Scp127 + { + /// + /// Invoked before SCP-127 voice line is played. + /// + public static Event Talking { get; set; } = new(); + + /// + /// Invoked after SCP-127 voice line is played. + /// + public static Event Talked { get; set; } = new(); + + /// + /// Invoked before SCP-127 gains experience. + /// + public static Event GainingExperience { get; set; } = new(); + + /// + /// Invoked after SCP-127 gains experience. + /// + public static Event GainedExperience { get; set; } = new(); + + /// + /// Called before SCP-127 voice line is played. + /// + /// The instance. + public static void OnTalking(Scp127TalkingEventArgs ev) + { + TalkingEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.VoiceLine, ev.Priority, ev.IsAllowed); + Talking.InvokeSafely(eventArgs); + + ev.Priority = eventArgs.Priority; + ev.VoiceLine = eventArgs.VoiceLine; + ev.IsAllowed = eventArgs.IsAllowed; + } + + /// + /// Called after SCP-127 voice line is played. + /// + /// The instance. + public static void OnTalked(Scp127TalkedEventArgs ev) + => Talked.InvokeSafely(new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.VoiceLine, ev.Priority)); + + /// + /// Called before SCP-127 gains experience. + /// + /// The instance. + public static void OnGainingExperience(Scp127GainingExperienceEventArgs ev) + { + GainingExperienceEventArgs eventArgs = new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.ExperienceGain, ev.IsAllowed); + GainingExperience.InvokeSafely(eventArgs); + + ev.ExperienceGain = eventArgs.Experience; + ev.IsAllowed = eventArgs.IsAllowed; + } + + /// + /// Called after SCP-127 gains experience. + /// + /// The instance. + public static void OnGainedExperience(Scp127GainExperienceEventArgs ev) => + GainedExperience.InvokeSafely(new(API.Features.Items.Item.Get(ev.Scp127Item.Base), ev.ExperienceGain)); + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Scp1507.cs b/EXILED/Exiled.Events/Handlers/Scp1507.cs index 63e4536d2c..f36b16d633 100644 --- a/EXILED/Exiled.Events/Handlers/Scp1507.cs +++ b/EXILED/Exiled.Events/Handlers/Scp1507.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.Handlers /// /// SCP-1507 related events. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public static class Scp1507 { /// diff --git a/EXILED/Exiled.Events/Handlers/Scp2536.cs b/EXILED/Exiled.Events/Handlers/Scp2536.cs index 3f7dfd1c58..8c0d272583 100644 --- a/EXILED/Exiled.Events/Handlers/Scp2536.cs +++ b/EXILED/Exiled.Events/Handlers/Scp2536.cs @@ -21,6 +21,11 @@ public static class Scp2536 /// public static Event FindingPosition { get; set; } = new(); + /// + /// Invoked once SCP-2536 has found a spawn location. + /// + public static Event FoundPosition { get; set; } = new(); + /// /// Invoked before SCP-2536 gives a gift to a player. /// @@ -37,6 +42,12 @@ public static class Scp2536 /// The instance. public static void OnFindingPosition(FindingPositionEventArgs ev) => FindingPosition.InvokeSafely(ev); + /// + /// Called after SCP-2536 chooses a target. + /// + /// The instance. + public static void OnFoundPosition(FoundPositionEventArgs ev) => FoundPosition.InvokeSafely(ev); + /// /// Called before SCP-2536 gives a gift to a player. /// diff --git a/EXILED/Exiled.Events/Handlers/Scp559.cs b/EXILED/Exiled.Events/Handlers/Scp559.cs index b17f520c9d..70d5387520 100644 --- a/EXILED/Exiled.Events/Handlers/Scp559.cs +++ b/EXILED/Exiled.Events/Handlers/Scp559.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.Handlers /// /// All SCP-559 related events. /// - [Obsolete("Only availaible for Christmas and AprilFools.")] + // [Obsolete("Only availaible for Christmas and AprilFools.")] public static class Scp559 { /// diff --git a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs index 0cb378ac02..1e7b55e3a8 100644 --- a/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs +++ b/EXILED/Exiled.Events/Patches/Events/Cassie/SendingCassieMessage.cs @@ -8,87 +8,61 @@ namespace Exiled.Events.Patches.Events.Cassie { using System.Collections.Generic; + using System.Linq; using System.Reflection.Emit; using API.Features.Pools; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Cassie; - + using global::Cassie; using Handlers; - using HarmonyLib; using Respawning; using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Cassie), nameof(Cassie.SendingCassieMessage))] - [HarmonyPatch(typeof(RespawnEffectsController), nameof(RespawnEffectsController.PlayCassieAnnouncement))] + [HarmonyPatch(typeof(CassieAnnouncementDispatcher), nameof(CassieAnnouncementDispatcher.PlayNewAnnouncement))] internal static class SendingCassieMessage { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); + Label skipLabel = generator.DefineLabel(); Label returnLabel = generator.DefineLabel(); + newInstructions[0].WithLabels(skipLabel); + newInstructions.InsertRange( 0, new CodeInstruction[] { - // words new(OpCodes.Ldarg_0), + new(OpCodes.Isinst, typeof(CassieScpTerminationAnnouncement)), + new(OpCodes.Brtrue_S, skipLabel), - // makeHold - new(OpCodes.Ldarg_1), - - // makeNoise - new(OpCodes.Ldarg_2), - - // customAnnouncement - new(OpCodes.Ldarg_3), - - // customSubtitles - new(OpCodes.Ldarg_S, 4), + new(OpCodes.Ldarg_0), // isAllowed new(OpCodes.Ldc_I4_1), - // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(string, bool, bool, bool, string, bool); - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs))[0]), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Dup), + // SendingCassieMessageEventArgs ev = new SendingCassieMessageEventArgs(CassieAnnouncement, bool); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCassieMessageEventArgs)).Single(ctor => ctor.GetParameters().Length == 2)), new(OpCodes.Dup), new(OpCodes.Dup), // Cassie.OnSendingCassieMessage(ev); new(OpCodes.Call, Method(typeof(Cassie), nameof(Cassie.OnSendingCassieMessage))), - // words = ev.Words - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Words))), + // annc = ev.Announcement + new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.Announcement))), new(OpCodes.Starg_S, 0), - // makeHold = ev.MakeHold - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeHold))), - new(OpCodes.Starg_S, 1), - - // makeNoise = ev.MakeNoise - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.MakeNoise))), - new(OpCodes.Starg_S, 2), - - // customAnnouncement = ev.IsCustomAnnouncement - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsCustomAnnouncement))), - new(OpCodes.Starg_S, 3), - - // customSubtitles = ev.CustomSubtitles - new(OpCodes.Call, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.CustomSubtitles))), - new(OpCodes.Starg_S, 4), - // if (!IsAllowed) // return; new(OpCodes.Callvirt, PropertyGetter(typeof(SendingCassieMessageEventArgs), nameof(SendingCassieMessageEventArgs.IsAllowed))), diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs b/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs new file mode 100644 index 0000000000..fec7811ecf --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs @@ -0,0 +1,65 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Item +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Item; + using HarmonyLib; + using InventorySystem.Items.MarshmallowMan; + + using static HarmonyLib.AccessTools; + + /// + /// Patch the . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Cackling))] + [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCackle))] + public class Cackling + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label retLabel = generator.DefineLabel(); + + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; + + newInstructions.InsertRange(index, new[] + { + // this; + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + + // true + new(OpCodes.Ldc_I4_1), + + // ev = new CacklingEventArgs(MarshmallowItem, bool); + new(OpCodes.Newobj, Constructor(typeof(CacklingEventArgs), new[] { typeof(MarshmallowItem), typeof(bool) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnCackling))), + + // if (!ev.IsAllowed) return + new(OpCodes.Callvirt, PropertyGetter(typeof(CacklingEventArgs), nameof(CacklingEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, retLabel), + }); + + newInstructions[newInstructions.Count - 1].WithLabels(retLabel); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs b/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs new file mode 100644 index 0000000000..15c74b57b1 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs @@ -0,0 +1,65 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Item +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Item; + using HarmonyLib; + using InventorySystem.Items.MarshmallowMan; + + using static HarmonyLib.AccessTools; + + /// + /// Patch the . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Punching))] + [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCmd))] + public class Punching + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label retLabel = generator.DefineLabel(); + + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; + + newInstructions[^1].WithLabels(retLabel); + + newInstructions.InsertRange(index, new[] + { + // this; + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + + // true + new(OpCodes.Ldc_I4_1), + + // ev = new PunchingEventArgs(MarshmallowItem, bool); + new(OpCodes.Newobj, Constructor(typeof(PunchingEventArgs), new[] { typeof(MarshmallowItem), typeof(bool) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnPunching))), + + // if (!ev.IsAllowed) return + new(OpCodes.Callvirt, PropertyGetter(typeof(PunchingEventArgs), nameof(PunchingEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, retLabel), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs index 0d53ebeefb..3033a0327d 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs @@ -7,6 +7,7 @@ namespace Exiled.Events.Patches.Events.Map { + using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; @@ -17,11 +18,12 @@ namespace Exiled.Events.Patches.Events.Map using Exiled.Events.EventArgs.Map; using HarmonyLib; using Respawning.Announcements; + using Subtitles; using static HarmonyLib.AccessTools; /// - /// Patches and + /// Patches and /// to add event. /// [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] @@ -30,8 +32,8 @@ internal static class AnnouncingChaosEntrance { private static IEnumerable TargetMethods() { - yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncementString)); - yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncementString)); + yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncement)); + yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncement)); } private static IEnumerable Transpiler(IEnumerable instruction, ILGenerator generator) @@ -70,6 +72,9 @@ private static IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncementString))] + [HarmonyPatch(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncement))] internal static class AnnouncingNtfEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -39,8 +40,8 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Stloc_3) + offset; + int offset = 2; + int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(UnitNamingRule), nameof(UnitNamingRule.TranslateToCassie)))) + offset; newInstructions.InsertRange( index, @@ -50,10 +51,10 @@ private static IEnumerable Transpiler(IEnumerable]*?>"), new(OpCodes.Ldsfld, Field(typeof(string), nameof(string.Empty))), new(OpCodes.Call, Method(typeof(Regex), nameof(Regex.Replace), new System.Type[] { typeof(string), typeof(string), typeof(string) })), @@ -63,9 +64,9 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable - /// Patch the + /// Patch the /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncementString))] + [HarmonyPatch(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncement))] internal static class AnnouncingNtfMiniEntrance { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -35,15 +35,17 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Stloc_1) + 1; + newInstructions.InsertRange( - 0, + index, new CodeInstruction[] { // WaveAnnouncementBase new(OpCodes.Ldarg_0), // scpsLeft - new(OpCodes.Ldloc_0), + new(OpCodes.Ldloc_1), // null new(OpCodes.Ldnull), @@ -66,7 +68,7 @@ private static IEnumerable Transpiler(IEnumerable /// Patches - /// . + /// . /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingScpTermination))] - [HarmonyPatch(typeof(NineTailedFoxAnnouncer), nameof(NineTailedFoxAnnouncer.AnnounceScpTermination))] + [HarmonyPatch(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.OnStartedPlaying))] internal static class AnnouncingScpTermination { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); - LocalBuilder ev = generator.DeclareLocal(typeof(AnnouncingScpTerminationEventArgs)); + LocalBuilder cause = generator.DeclareLocal(typeof(string)); + LocalBuilder enumerator = generator.DeclareLocal(typeof(IEnumerator)); + + ExceptionBlock beginTry = new(ExceptionBlockType.BeginExceptionBlock); + ExceptionBlock beginFinally = new(ExceptionBlockType.BeginFinallyBlock); + ExceptionBlock endFinally = new(ExceptionBlockType.EndExceptionBlock); Label ret = generator.DefineLabel(); + Label entryLabel = generator.DefineLabel(); + Label loopLabel = generator.DefineLabel(); + Label leaveLabel = generator.DefineLabel(); + Label endFinallyLabel = generator.DefineLabel(); + + int offset = -1; + int index = newInstructions.FindIndex(i => i.LoadsField(Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts)))) + offset; + + newInstructions.RemoveRange(index, 2); + newInstructions.Insert(index, new CodeInstruction(OpCodes.Ldloc_S, cause)); - int offset = -4; - int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Newobj && (ConstructorInfo)i.operand == GetDeclaredConstructors(typeof(LabApi.Events.Arguments.ServerEvents.CassieQueuingScpTerminationEventArgs))[0]) + offset; + newInstructions[0].WithLabels(leaveLabel); newInstructions.InsertRange( - index, + 0, new[] - { - // Player.Get(scp) - new CodeInstruction(OpCodes.Ldarg_0), - new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), - - // hit - new(OpCodes.Ldarg_1), - - // AnnouncingScpTerminationEventArgs ev = new(Player, DamageHandlerBase) - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(AnnouncingScpTerminationEventArgs))[0]), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Stloc_S, ev.LocalIndex), - - // Map.OnAnnouncingScpTermination(ev) - new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), - - // if (!ev.IsAllowed) - // return; - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.IsAllowed))), - new(OpCodes.Brfalse_S, ret), - - // hit = ev.DamageHandler.Base - new(OpCodes.Ldloc_S, ev.LocalIndex), - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.DamageHandler))), - new(OpCodes.Callvirt, PropertyGetter(typeof(CustomDamageHandler), nameof(CustomDamageHandler.Base))), - new(OpCodes.Starg, 1), - - // announcement = ev.TerminationCause - new(OpCodes.Ldloc_S, ev.LocalIndex), - new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), - new(OpCodes.Stloc_0), - }); + { + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, Field(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement._announcementTts))), + new(OpCodes.Stloc_S, cause), + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(CassieScpTerminationAnnouncement), nameof(CassieScpTerminationAnnouncement.Victims))), + new(OpCodes.Callvirt, Method(typeof(IEnumerable), nameof(IEnumerable.GetEnumerator))), + new(OpCodes.Stloc_S, enumerator), + + // start of try + new CodeInstruction(OpCodes.Br_S, entryLabel).WithBlocks(beginTry), + + // start of loop + new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(loopLabel), + new(OpCodes.Callvirt, PropertyGetter(typeof(IEnumerator), nameof(IEnumerator.Current))), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(Footprint) })), + new(OpCodes.Ldloc_S, cause), + new(OpCodes.Newobj, Constructor(typeof(AnnouncingScpTerminationEventArgs), new[] { typeof(Player), typeof(string) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Map), nameof(Map.OnAnnouncingScpTermination))), + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingScpTerminationEventArgs), nameof(AnnouncingScpTerminationEventArgs.TerminationCause))), + new(OpCodes.Stloc_S, cause), + + // entry point + new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithLabels(entryLabel), + new(OpCodes.Callvirt, Method(typeof(IEnumerator), nameof(IEnumerator.MoveNext))), + new(OpCodes.Brtrue_S, loopLabel), + + // end of loop + new(OpCodes.Leave, leaveLabel), + + // begin finally + new CodeInstruction(OpCodes.Ldloc_S, enumerator).WithBlocks(beginFinally), + new(OpCodes.Brfalse, endFinallyLabel), + new(OpCodes.Ldloc_S, enumerator), + new(OpCodes.Callvirt, Method(typeof(IDisposable), nameof(IDisposable.Dispose))), + + // end of finally + new CodeInstruction(OpCodes.Endfinally).WithLabels(endFinallyLabel).WithBlocks(endFinally), + }); newInstructions[newInstructions.Count - 1].labels.Add(ret); diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs deleted file mode 100644 index 7193f8d17f..0000000000 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingTeamEntrance.cs +++ /dev/null @@ -1,68 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Patches.Events.Map -{ - using System.Collections.Generic; - using System.Reflection; - using System.Reflection.Emit; - using System.Text; - - using Exiled.API.Features.Pools; - using Exiled.Events.Attributes; - using Exiled.Events.EventArgs.Map; - using HarmonyLib; - using Respawning.Announcements; - - using static HarmonyLib.AccessTools; - - /// - /// Patches to prevent cassie from playing empty string. - /// - [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingNtfEntrance))] - [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] - [HarmonyPatch(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.PlayAnnouncement))] - internal static class AnnouncingTeamEntrance - { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - List newInstructions = ListPool.Pool.Get(instructions); - - Label returnLabel = generator.DefineLabel(); - - // the instruction that sends subtitles is called before stringReturn is created (and thus checked) so we need to move it so that empty (or disallowed) message's subtitles are not sent. - // this removes the Ldarg_0 and the CallVirt - int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.SendSubtitles)))); - CodeInstruction sendSubtitlesInstruction = newInstructions[index]; - newInstructions.RemoveRange(index - 2, 3); - - index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldsfld); - - newInstructions.InsertRange(index, new[] - { - // if (stringReturn == "") - // return; - new(OpCodes.Ldloc_S, 4), - new(OpCodes.Ldstr, string.Empty), - new(OpCodes.Ceq), - new(OpCodes.Brtrue_S, returnLabel), - - // send subtitles before cassie message, but after our check. - new(OpCodes.Ldarg_0), - new(OpCodes.Ldarg_1), - sendSubtitlesInstruction, - }); - - newInstructions[newInstructions.Count - 1].labels.Add(returnLabel); - - for (int z = 0; z < newInstructions.Count; z++) - yield return newInstructions[z]; - - ListPool.Pool.Return(newInstructions); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs index b379bdec1a..4af8bd4e11 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningRoomConnector.cs @@ -89,14 +89,13 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(RoomConnectorSpawnpointBase), nameof(RoomConnectorSpawnpointBase.SetupAllRoomConnectors)))); - List /// The players to affect. /// The fake role. - /// /// The Unit ID of the player, if is an NTF role. - public void SetAppearance(IEnumerable viewers, RoleTypeId fakeRole, byte unitId = 0) + /// How to handle edge cases. + /// The Unit ID of the player, if is an NTF role. + public void SetAppearance(IEnumerable viewers, RoleTypeId fakeRole, RoleData.Authority authority = RoleData.Authority.None, byte unitId = 0) { foreach (Player player in viewers) { - player.SetAppearance(this, fakeRole, unitId); + player.SetAppearance(this, fakeRole, authority, unitId); } } @@ -1887,10 +1888,11 @@ public void SetAppearance(IEnumerable viewers, RoleTypeId fakeRole, byte /// /// The target. /// The fake role. + /// How to handle edge cases. /// The Unit ID of the player, if is an NTF role. - public void SetAppearance(Player player, RoleTypeId fakeRole, byte unitId = 0) + public void SetAppearance(Player player, RoleTypeId fakeRole, RoleData.Authority authority = RoleData.Authority.None, byte unitId = 0) { - FakeRoles[player] = new RoleData(fakeRole, unitId); + FakeRoles[player] = new RoleData(fakeRole, authority, unitId); } /// diff --git a/EXILED/Exiled.API/Structs/RoleData.cs b/EXILED/Exiled.API/Structs/RoleData.cs index 7497b6d0a3..2d04b0bd0e 100644 --- a/EXILED/Exiled.API/Structs/RoleData.cs +++ b/EXILED/Exiled.API/Structs/RoleData.cs @@ -9,6 +9,7 @@ namespace Exiled.API.Structs { using System; + using Mirror; using PlayerRoles; /// @@ -20,13 +21,43 @@ public struct RoleData : IEquatable /// Initializes a new instance of the struct. /// /// The fake role. + /// The authority of the role data. /// The fake UnitID, if is an NTF role. - public RoleData(RoleTypeId role = RoleTypeId.None, byte unitId = 0) + public RoleData(RoleTypeId role = RoleTypeId.None, Authority authority = Authority.None, byte unitId = 0) { Role = role; + DataAuthority = authority; UnitId = unitId; } + /// + /// Represents flags for how Exiled should handle edge cases. + /// + [Flags] + public enum Authority + { + /// + /// Indicates Exiled should only fake the role of the target of this in ideal conditions. + /// + None = 0, + + /// + /// Indicates that Exiled should attempt to override other plugins fake role attempts if they exist. + /// + /// This is not guaranteed to always work. + Override = 1, + + /// + /// Indicates that the fake role should always be sent without checking if the player is dead, etc... + /// + Always = 2, + + /// + /// Indicates that Exiled should not reset the fake role if the target of this dies. + /// + Persist = 4, + } + /// /// Gets the static representing no data. /// @@ -42,6 +73,17 @@ public RoleData(RoleTypeId role = RoleTypeId.None, byte unitId = 0) /// public byte UnitId { get; set; } + /// + /// Gets or sets the authority of this instance. see for details. + /// + public Authority DataAuthority { get; set; } = Authority.None; + + /// + /// Gets or sets custom data written to network writers when fake data is generated. + /// + /// Leave this value as null unless you are writing custom role-specific data. + public Action CustomData { get; set; } + /// /// Checks if 2 are equal. /// @@ -59,18 +101,12 @@ public RoleData(RoleTypeId role = RoleTypeId.None, byte unitId = 0) public static bool operator !=(RoleData left, RoleData right) => !left.Equals(right); /// - public bool Equals(RoleData other) => Role == other.Role && UnitId == other.UnitId; + public bool Equals(RoleData other) => Role == other.Role && DataAuthority == other.DataAuthority && UnitId == other.UnitId; /// public override bool Equals(object obj) => obj is RoleData other && Equals(other); /// - public override int GetHashCode() - { - unchecked - { - return ((int)Role * 397) ^ UnitId.GetHashCode(); - } - } + public override int GetHashCode() => HashCode.Combine((int)Role, UnitId, (int)DataAuthority, CustomData); } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index adae6e21a8..876ccf1f37 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -70,6 +70,7 @@ public override void OnEnabled() Handlers.Server.RoundStarted += Handlers.Internal.Round.OnRoundStarted; Handlers.Player.ChangingRole += Handlers.Internal.Round.OnChangingRole; Handlers.Player.Spawned += Handlers.Internal.Round.OnSpawned; + Handlers.Player.Dying.Subscribe(Handlers.Internal.Round.OnDying, -100); Handlers.Player.SpawningRagdoll += Handlers.Internal.Round.OnSpawningRagdoll; Handlers.Scp049.ActivatingSense += Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified += Handlers.Internal.Round.OnVerified; @@ -121,6 +122,7 @@ public override void OnDisabled() Handlers.Server.RoundStarted -= Handlers.Internal.Round.OnRoundStarted; Handlers.Player.ChangingRole -= Handlers.Internal.Round.OnChangingRole; Handlers.Player.Spawned -= Handlers.Internal.Round.OnSpawned; + Handlers.Player.Dying -= Handlers.Internal.Round.OnDying; Handlers.Player.SpawningRagdoll -= Handlers.Internal.Round.OnSpawningRagdoll; Handlers.Scp049.ActivatingSense -= Handlers.Internal.Round.OnActivatingSense; Handlers.Player.Verified -= Handlers.Internal.Round.OnVerified; diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 3c91147c1d..3cbe9d3c1d 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -34,6 +34,8 @@ namespace Exiled.Events.Handlers.Internal using PlayerRoles; using PlayerRoles.FirstPersonControl; using PlayerRoles.RoleAssign; + using RelativePositioning; + using Respawning.NamingRules; using UnityEngine; using Utils.Networking; using Utils.NonAllocLINQ; @@ -91,8 +93,11 @@ public static void OnChangingRole(ChangingRoleEventArgs ev) /// public static void OnSpawned(SpawnedEventArgs ev) { - foreach (Player viewer in Player.Enumerable.Except(new[] { ev.Player })) + foreach (Player viewer in Player.Enumerable) { + if (viewer == ev.Player) + continue; + foreach (Func generator in ev.Player.FakeRoleGenerator) { RoleData data = generator(viewer); @@ -104,6 +109,22 @@ public static void OnSpawned(SpawnedEventArgs ev) } } + /// + public static void OnDying(DyingEventArgs ev) + { + if (!ev.IsAllowed) + return; + + foreach (Player viewer in Player.Enumerable) + { + if (viewer == ev.Player) + continue; + + if (viewer.FakeRoles.TryGetValue(ev.Player, out RoleData data) && (data.DataAuthority & RoleData.Authority.Persist) == RoleData.Authority.None) + viewer.FakeRoles.Remove(ev.Player); + } + } + /// public static void OnSpawningRagdoll(SpawningRagdollEventArgs ev) { @@ -173,8 +194,53 @@ public static RoleTypeId OnRoleSyncEvent(ReferenceHub ownerHub, ReferenceHub vie if (viewer.FakeRoles.TryGetValue(owner, out RoleData data)) { - if (data.UnitId != 0) - writer.WriteByte(data.UnitId); + if (data.Role == actualRole) + return actualRole; + + // if another plugin has written data, we can't reliably modify and expect non-breaking behavior. + // if we send faulty data we can accidentally soft-dc the entire server which is much worse than a plugin not working. + if (writer.Position != 0 && (data.DataAuthority & RoleData.Authority.Override) == RoleData.Authority.None) + return actualRole; + + writer.Position = 0; + + // I doubt most devs want people who are dead to have fake roles. + if (actualRole.IsDead() && (data.DataAuthority & RoleData.Authority.Always) == RoleData.Authority.None) + return actualRole; + + if (data.CustomData != null) + { + data.CustomData(writer); + } + else + { + if (data.Role.GetRoleBase() is PlayerRoles.HumanRole { UsesUnitNames: true }) + { + if (data.UnitId != 0) + { + writer.WriteByte(data.UnitId); + } + else + { + if (!NamingRulesManager.GeneratedNames.TryGetValue(Team.FoundationForces, out List list)) + return actualRole; + + writer.WriteByte((byte)list.Count); + } + } + + if (data.Role.GetRoleBase() is PlayerRoles.PlayableScps.Scp1507.Scp1507Role flamingo) + writer.WriteByte((byte)flamingo.ServerSpawnReason); + + if (data.Role == RoleTypeId.Scp0492) + { + writer.WriteUShort((ushort)Mathf.Clamp(Mathf.CeilToInt(owner.MaxHealth), 0, ushort.MaxValue)); + writer.WriteBool(false); + } + + writer.WriteRelativePosition(new RelativePosition(owner.Position)); + writer.WriteUShort((ushort)Mathf.RoundToInt(Mathf.InverseLerp(0.0f, 360f, owner.Rotation.eulerAngles.y) * ushort.MaxValue)); + } return data.Role; } From 1ed1adc7902d67ba455a88ea4c5267b479482900 Mon Sep 17 00:00:00 2001 From: "@Someone" <45270312+Someone-193@users.noreply.github.com> Date: Tue, 6 Jan 2026 13:57:30 -0500 Subject: [PATCH 10/10] Add AllowSelf flag + minor optimization --- EXILED/Exiled.API/Structs/RoleData.cs | 5 ++++ .../Exiled.Events/Handlers/Internal/Round.cs | 30 ++++++++++--------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/EXILED/Exiled.API/Structs/RoleData.cs b/EXILED/Exiled.API/Structs/RoleData.cs index 2d04b0bd0e..ae65f305bc 100644 --- a/EXILED/Exiled.API/Structs/RoleData.cs +++ b/EXILED/Exiled.API/Structs/RoleData.cs @@ -56,6 +56,11 @@ public enum Authority /// Indicates that Exiled should not reset the fake role if the target of this dies. /// Persist = 4, + + /// + /// Indicates that this can make a player view themselves as a different role. + /// + AffectSelf = 8, } /// diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 3cbe9d3c1d..2f4e76d15a 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -95,13 +95,14 @@ public static void OnSpawned(SpawnedEventArgs ev) { foreach (Player viewer in Player.Enumerable) { - if (viewer == ev.Player) - continue; - foreach (Func generator in ev.Player.FakeRoleGenerator) { RoleData data = generator(viewer); - if (data.Role != RoleTypeId.None) + + if (data.Role == RoleTypeId.None) + continue; + + if (viewer != ev.Player || (data.DataAuthority & RoleData.Authority.AffectSelf) == RoleData.Authority.AffectSelf) { viewer.FakeRoles[ev.Player] = data; } @@ -117,9 +118,6 @@ public static void OnDying(DyingEventArgs ev) foreach (Player viewer in Player.Enumerable) { - if (viewer == ev.Player) - continue; - if (viewer.FakeRoles.TryGetValue(ev.Player, out RoleData data) && (data.DataAuthority & RoleData.Authority.Persist) == RoleData.Authority.None) viewer.FakeRoles.Remove(ev.Player); } @@ -165,15 +163,16 @@ public static void OnVerified(VerifiedEventArgs ev) { player.SetFakeScale(player.Scale, new List() { ev.Player }); - if (player != ev.Player) + foreach (Func generator in player.FakeRoleGenerator) { - foreach (Func generator in player.FakeRoleGenerator) + RoleData data = generator(ev.Player); + + if (data.Role == RoleTypeId.None) + continue; + + if (player != ev.Player || (data.DataAuthority & RoleData.Authority.AffectSelf) == RoleData.Authority.AffectSelf) { - RoleData data = generator(ev.Player); - if (data.Role != RoleTypeId.None) - { - ev.Player.FakeRoles[player] = data; - } + ev.Player.FakeRoles[player] = data; } } } @@ -197,6 +196,9 @@ public static RoleTypeId OnRoleSyncEvent(ReferenceHub ownerHub, ReferenceHub vie if (data.Role == actualRole) return actualRole; + if (ownerHub.roleManager.PreviouslySentRole.TryGetValue(viewerHub.netId, out RoleTypeId previousRole) && previousRole == data.Role) + return data.Role; + // if another plugin has written data, we can't reliably modify and expect non-breaking behavior. // if we send faulty data we can accidentally soft-dc the entire server which is much worse than a plugin not working. if (writer.Position != 0 && (data.DataAuthority & RoleData.Authority.Override) == RoleData.Authority.None)