Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions EXILED/Exiled.API/Features/Roles/Scp939Role.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ internal Scp939Role(Scp939GameRole baseRole)
/// </summary>
~Scp939Role() => ListPool<Player>.Pool.Return(VisiblePlayers);

/// <summary>
/// Gets a list of players who are turned away from SCP-939 AmnesticCloud Ability.
/// </summary>
public static HashSet<Player> TurnedPlayers { get; } = new(20);

/// <inheritdoc/>
public override RoleTypeId Type { get; } = RoleTypeId.Scp939;

Expand Down
6 changes: 6 additions & 0 deletions EXILED/Exiled.Events/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ public sealed class Config : IConfig
[Description("Indicates whether SCP-049 can sense tutorial players")]
public bool CanScp049SenseTutorial { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether Tutorial is affected by Scp-939 Amnestic Cloud.
/// </summary>
[Description("Indicates whether Tutorial is affected by Scp-939 Amnestic Cloud")]
public bool TutorialAffectedByScp939AmnesticCloud { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether tutorial is affected by SCP-079 scan.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions EXILED/Exiled.Events/Handlers/Internal/Round.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public static void OnRestartingRound()
Scp173Role.TurnedPlayers.Clear();
Scp096Role.TurnedPlayers.Clear();
Scp079Role.TurnedPlayers.Clear();
Scp939Role.TurnedPlayers.Clear();

MultiAdminFeatures.CallEvent(MultiAdminFeatures.EventType.ROUND_END);

Expand Down
85 changes: 85 additions & 0 deletions EXILED/Exiled.Events/Patches/Generic/StayAtAmnesticCloud.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// -----------------------------------------------------------------------
// <copyright file="StayAtAmnesticCloud.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.Patches.Generic
{
using System.Collections.Generic;
using System.Reflection.Emit;

using Exiled.API.Features;
using Exiled.API.Features.Pools;
using HarmonyLib;
using PlayerRoles;
using PlayerRoles.PlayableScps.Scp939;

using static HarmonyLib.AccessTools;

using ExiledEvents = Exiled.Events.Events;
using Scp939Role = API.Features.Roles.Scp939Role;

/// <summary>
/// Patches <see cref="PlayerRoles.PlayableScps.Scp939.Scp939AmnesticCloudInstance.OnStay(ReferenceHub)"/>.
/// <see cref="Config.TutorialAffectedByScp939AmnesticCloud"/>.
/// </summary>
[HarmonyPatch(typeof(Scp939AmnesticCloudInstance), nameof(Scp939AmnesticCloudInstance.OnStay))]
internal static class StayAtAmnesticCloud
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);

Label continueLabel = generator.DefineLabel();

Label returnLabel = generator.DefineLabel();

// Second check pointer
// We use it to pass execution
// to the second check if the first check fails,
// otherwise the second check won't be executed
Label secondCheckPointer = generator.DefineLabel();

newInstructions[0].WithLabels(continueLabel);

// if (referenceHub.roleManager.CurrentRole.RoleTypeId == RoleTypeId.Tutorial && ExiledEvents.Instance.Config.TutorialAffectedByScp939AmnesticCloud
// || Scp939Role.TurnedPlayers.Contains(Player.Get(referenceHub)))
// return;
newInstructions.InsertRange(
0,
new[]
{
// if ((referenceHub.roleManager.CurrentRole.RoleTypeId == RoleTypeId.Tutorial &&
new(OpCodes.Ldarg_1),
new(OpCodes.Ldfld, Field(typeof(ReferenceHub), nameof(ReferenceHub.roleManager))),
new(OpCodes.Callvirt, PropertyGetter(typeof(PlayerRoleManager), nameof(PlayerRoleManager.CurrentRole))),
new(OpCodes.Callvirt, PropertyGetter(typeof(PlayerRoleBase), nameof(PlayerRoleBase.RoleTypeId))),
new(OpCodes.Ldc_I4_S, (sbyte)RoleTypeId.Tutorial),
new(OpCodes.Bne_Un_S, secondCheckPointer),

// ExiledEvents.Instance.Config.TutorialAffectedByScp939AmnesticCloud)
new(OpCodes.Call, PropertyGetter(typeof(ExiledEvents), nameof(ExiledEvents.Instance))),
new(OpCodes.Callvirt, PropertyGetter(typeof(Plugin<Config>), nameof(Plugin<Config>.Config))),
new(OpCodes.Callvirt, PropertyGetter(typeof(Config), nameof(Config.TutorialAffectedByScp939AmnesticCloud))),
new(OpCodes.Brtrue_S, returnLabel),

// || Scp939Role.TurnedPlayers.Contains(Player.Get(referenceHub))
new CodeInstruction(OpCodes.Call, PropertyGetter(typeof(Scp939Role), nameof(Scp939Role.TurnedPlayers))).WithLabels(secondCheckPointer),
new(OpCodes.Ldarg_1),
new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
new(OpCodes.Callvirt, Method(typeof(HashSet<Player>), nameof(HashSet<Player>.Contains))),
new(OpCodes.Brfalse_S, continueLabel),

// return;
new CodeInstruction(OpCodes.Ret).WithLabels(returnLabel),
});

for (int i = 0; i < newInstructions.Count; i++)
yield return newInstructions[i];

ListPool<CodeInstruction>.Pool.Return(newInstructions);
}
}
}