diff --git a/EXILED/Exiled.API/Enums/CameraType.cs b/EXILED/Exiled.API/Enums/CameraType.cs
index 535e7366ce..1a193d16db 100644
--- a/EXILED/Exiled.API/Enums/CameraType.cs
+++ b/EXILED/Exiled.API/Enums/CameraType.cs
@@ -159,6 +159,8 @@ public enum CameraType
EzGateAElevators,
EzGateBInterior,
EzGateBSide,
+ EzGateAStairwell,
+ EzGateAUpper,
#endregion
}
}
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/Features/Camera.cs b/EXILED/Exiled.API/Features/Camera.cs
index fca5cbbc73..4601a5ada1 100644
--- a/EXILED/Exiled.API/Features/Camera.cs
+++ b/EXILED/Exiled.API/Features/Camera.cs
@@ -143,6 +143,8 @@ 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,
// 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..42f0911ddd 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.
@@ -70,7 +65,7 @@ public static void MessageTranslated(string message, string translation, bool is
for (int i = 0; i < cassies.Length; i++)
announcement.Append($"{translations[i].Replace(' ', ' ')} {cassies[i]} ");
- RespawnEffectsController.PlayCassieAnnouncement(announcement.ToString(), isHeld, isNoisy, isSubtitles);
+ new CassieAnnouncement(new CassieTtsPayload(message, isSubtitles, isHeld), 0f, isNoisy ? 1 : 0).AddToQueue();
StringBuilderPool.Pool.Return(announcement);
}
@@ -81,7 +76,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 +87,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 +97,45 @@ 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.
- /// Determines if a number won't be converted to its full pronunciation.
- /// The speed of the message.
+ /// An obsolete parameter.
+ /// Another obsolete parameter.
/// 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, bool obsolete1, float obsolete2)
+ {
+ 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 +143,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 FLAMINGOS",
+ _ => "UNKNOWN",
+ };
///
/// Converts a number into a Cassie-Readable String.
@@ -129,7 +160,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 +184,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 +214,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/Items/Jailbird.cs b/EXILED/Exiled.API/Features/Items/Jailbird.cs
index b68a3473c2..7e67d0cc73 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,8 +79,8 @@ public float FlashDuration
///
public float ConcussionDuration
{
- get => Base._hitreg._concussionDuration;
- set => Base._hitreg._concussionDuration = value;
+ get => Base._concussionDuration;
+ set => Base._concussionDuration = value;
}
///
@@ -88,8 +88,8 @@ public float ConcussionDuration
///
public float Radius
{
- get => Base._hitreg._hitregRadius;
- set => Base._hitreg._hitregRadius = value;
+ get => Radius;
+ set => Radius = 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/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/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index ea317a5d5d..e635bfd650 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -1982,6 +1982,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.
///
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/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.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/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/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/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/Scp079/Recontaining.cs b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs
index d2efcd3fd3..680bbbf0dd 100644
--- a/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs
+++ b/EXILED/Exiled.Events/Patches/Events/Scp079/Recontaining.cs
@@ -31,17 +31,18 @@ internal class Recontaining
{
private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
{
- int index = 0;
List newInstructions = ListPool.Pool.Get(instructions);
LocalBuilder ev = generator.DeclareLocal(typeof(RecontainingEventArgs));
Label returnLabel = generator.DefineLabel();
- newInstructions.InsertRange(index, new CodeInstruction[]
+ int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + 1;
+
+ newInstructions.InsertRange(index, new[]
{
// RecontainingEventArgs ev = new(this._activatorGlass)
- new(OpCodes.Ldarg_0),
+ new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]),
new(OpCodes.Ldfld, Field(typeof(Scp079Recontainer), nameof(Scp079Recontainer._activatorGlass))),
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RecontainingEventArgs))[0]),
new(OpCodes.Stloc_S, ev.LocalIndex),
diff --git a/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs b/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs
index 1f6a8ee431..17bdf5e142 100644
--- a/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs
+++ b/EXILED/Exiled.Events/Patches/Fixes/Jailbird914CoarseFix.cs
@@ -22,7 +22,7 @@ namespace Exiled.Events.Patches.Fixes
using static HarmonyLib.AccessTools;
///
- /// Patches .
+ /// Patches .
/// Bug reported to NW (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/88).
///
[HarmonyPatch(typeof(JailbirdDeteriorationTracker), nameof(JailbirdDeteriorationTracker.Setup))]
diff --git a/EXILED/Exiled.Events/Patches/Fixes/JailbirdHitRegFix.cs b/EXILED/Exiled.Events/Patches/Fixes/JailbirdHitRegFix.cs
deleted file mode 100644
index 46151c7577..0000000000
--- a/EXILED/Exiled.Events/Patches/Fixes/JailbirdHitRegFix.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-// -----------------------------------------------------------------------
-//
-// Copyright (c) ExMod Team. All rights reserved.
-// Licensed under the CC BY-SA 3.0 license.
-//
-// -----------------------------------------------------------------------
-
-namespace Exiled.Events.Patches.Fixes
-{
- using System.Collections.Generic;
- using System.Reflection.Emit;
-
- using API.Features.Pools;
-
- using HarmonyLib;
- using InventorySystem.Items.Jailbird;
- using Mirror;
- using Utils.Networking;
-
- using static HarmonyLib.AccessTools;
-
- ///
- /// Patches .
- ///
- [HarmonyPatch(typeof(JailbirdHitreg), nameof(JailbirdHitreg.ServerAttack))]
- internal static class JailbirdHitRegFix
- {
- private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
- {
- List newInstructions = ListPool.Pool.Get(instructions);
-
- int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(ReferenceHubReaderWriter), nameof(ReferenceHubReaderWriter.TryReadReferenceHub)))) - 2;
-
- int breakIndex = newInstructions.FindIndex(i => i.Calls(Method(typeof(JailbirdHitreg), nameof(JailbirdHitreg.DetectDestructibles)))) - 1;
- Label breakLabel = generator.DefineLabel();
- newInstructions[breakIndex].WithLabels(breakLabel);
-
- List