diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/ISnakeEvent.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/ISnakeEvent.cs new file mode 100644 index 0000000000..b2a3cda8ca --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/ISnakeEvent.cs @@ -0,0 +1,28 @@ +// ----------------------------------------------------------------------- +// +// 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; + using InventorySystem.Items.Keycards.Snake; + + /// + /// Event args used for all related events. + /// + public interface ISnakeEvent : IPlayerEvent + { + /// + /// Gets the Snake game controller. + /// + public SnakeEngine Engine { get; } + + /// + /// Gets the keycard that triggered this event. + /// + public Keycard Keycard { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Snake/GainedScoreEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Snake/GainedScoreEventArgs.cs new file mode 100644 index 0000000000..d1ac92e0ee --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Snake/GainedScoreEventArgs.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Snake +{ + using Exiled.API.Features.Items; + using Interfaces; + using InventorySystem.Items.Keycards.Snake; + + /// + /// Contains all information after a player gains score in the Snake minigame. + /// + public class GainedScoreEventArgs : ISnakeEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The instance. + /// The who triggered this event. + /// The triggering this event. + public GainedScoreEventArgs(SnakeEngine engine, API.Features.Player player, Keycard keycard) + { + Engine = engine; + Player = player; + Score = engine.Score; + Keycard = keycard; + } + + /// + public SnakeEngine Engine { get; } + + /// + /// Gets the person playing the game. + /// + public API.Features.Player Player { get; } + + /// + public Keycard Keycard { get; } + + /// + /// Gets the newly obtained score. + /// + public int Score { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Snake/GameOverEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Snake/GameOverEventArgs.cs new file mode 100644 index 0000000000..fe9498324e --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Snake/GameOverEventArgs.cs @@ -0,0 +1,55 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Snake +{ + using Exiled.API.Features.Items; + using Interfaces; + using InventorySystem.Items.Keycards.Snake; + + /// + /// Contains all information after a player loses at Snake. + /// + public class GameOverEventArgs : ISnakeEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The instance. + /// The who triggered this event. + /// The triggering this event. + public GameOverEventArgs(SnakeEngine engine, API.Features.Player player, Keycard keycard) + { + Engine = engine; + Player = player; + FinalScore = engine.Score; + Length = engine.CurLength; + Keycard = keycard; + } + + /// + public SnakeEngine Engine { get; } + + /// + /// Gets the person playing the game. + /// + public API.Features.Player Player { get; } + + /// + public Keycard Keycard { get; } + + /// + /// Gets the final score. + /// + public int FinalScore { get; } + + /// + /// Gets the final length of the snake. + /// + public int Length { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Snake/NewGameEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Snake/NewGameEventArgs.cs new file mode 100644 index 0000000000..4a96c0df1e --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Snake/NewGameEventArgs.cs @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Snake +{ + using Exiled.API.Features.Items; + using Interfaces; + using InventorySystem.Items.Keycards.Snake; + + /// + /// Contains all information when a player starts a new snake game. + /// + public class NewGameEventArgs : ISnakeEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The instance. + /// The who triggered this event. + /// The triggering this event. + public NewGameEventArgs(SnakeEngine engine, API.Features.Player player, Keycard keycard) + { + Engine = engine; + Player = player; + Keycard = keycard; + } + + /// + public SnakeEngine Engine { get; } + + /// + /// Gets the person playing the game. + /// + public API.Features.Player Player { get; } + + /// + public Keycard Keycard { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Exiled.Events.csproj b/EXILED/Exiled.Events/Exiled.Events.csproj index 620625057d..528d035ba6 100644 --- a/EXILED/Exiled.Events/Exiled.Events.csproj +++ b/EXILED/Exiled.Events/Exiled.Events.csproj @@ -37,6 +37,7 @@ + diff --git a/EXILED/Exiled.Events/Handlers/Snake.cs b/EXILED/Exiled.Events/Handlers/Snake.cs new file mode 100644 index 0000000000..8b2d3e2e89 --- /dev/null +++ b/EXILED/Exiled.Events/Handlers/Snake.cs @@ -0,0 +1,62 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Handlers +{ +#pragma warning disable SA1623 // Property summary documentation should match accessors + + using Exiled.Events.EventArgs.Snake; + using Features; + + /// + /// Handles Snake related events. + /// + public class Snake + { + /// + /// Invoked when gaining score in Snake. + /// + public static Event GainedScore { get; set; } = new(); + + /// + /// Invoked when a player loses in Snake. + /// + public static Event GameOver { get; set; } = new(); + + /// + /// Invoked when a player starts a new game. + /// + public static Event NewGame { get; set; } = new(); + + /// + /// Called when a player gains score in Snake. + /// + /// The instance. + public static void OnGainedScore(GainedScoreEventArgs ev) + { + GainedScore.InvokeSafely(ev); + } + + /// + /// Called when a player loses in Snake. + /// + /// The instance. + public static void OnGameOver(GameOverEventArgs ev) + { + GameOver.InvokeSafely(ev); + } + + /// + /// Called when a player starts a new game in Snake. + /// + /// The instance. + public static void OnNewGame(NewGameEventArgs ev) + { + NewGame.InvokeSafely(ev); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Snake/ChaosKeycard.cs b/EXILED/Exiled.Events/Patches/Events/Snake/ChaosKeycard.cs new file mode 100644 index 0000000000..f17b99c056 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Snake/ChaosKeycard.cs @@ -0,0 +1,61 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Snake +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Attributes; + using Exiled.API.Features.Items; + using HarmonyLib; + using InventorySystem.Items.Keycards; + using InventorySystem.Items.Keycards.Snake; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// + [EventPatch(typeof(Handlers.Snake), nameof(Handlers.Snake.GainedScore))] + [EventPatch(typeof(Handlers.Snake), nameof(Handlers.Snake.GameOver))] + [EventPatch(typeof(Handlers.Snake), nameof(Handlers.Snake.NewGame))] + [HarmonyPatch(typeof(ChaosKeycardItem), nameof(ChaosKeycardItem.ServerProcessCustomCmd))] + internal static class ChaosKeycard + { + private static IEnumerable Transpiler(IEnumerable instructions) + { + CodeMatcher matcher = new CodeMatcher(instructions) + .MatchEndForward(new CodeMatch(OpCodes.Ldc_I4_1)) + .Advance(-1) + .Insert( + new(OpCodes.Ldarg_0), + new(OpCodes.Ldloc_1), + new(OpCodes.Call, Method(typeof(ChaosKeycard), nameof(OnCardUse)))); + + return matcher.InstructionEnumeration(); + } + + private static void OnCardUse(ChaosKeycardItem itemBase, SnakeNetworkMessage message) + { + Keycard item = Item.Get(itemBase); + API.Features.Player player = item.Owner; + + if (!ChaosKeycardItem.SnakeSessions.TryGetValue(item.Serial, out SnakeEngine engine)) + return; + + bool isNewGame = message.HasFlag(SnakeNetworkMessage.SyncFlags.GameReset); + + if(message.HasFlag(SnakeNetworkMessage.SyncFlags.HasNewFood) && !isNewGame) + Handlers.Snake.OnGainedScore(new (engine, player, item)); + else if (message.HasFlag(SnakeNetworkMessage.SyncFlags.GameOver)) + Handlers.Snake.OnGameOver(new(engine, player, item)); + else if (isNewGame) + Handlers.Snake.OnNewGame(new(engine, player, item)); + } + } +} \ No newline at end of file