From d5e61ea3a2618d1cc125b92f639dbefce9ea26e0 Mon Sep 17 00:00:00 2001 From: Extremelyd1 Date: Mon, 2 Oct 2023 21:34:52 +0200 Subject: [PATCH] Allow player attacks to be parried and fix nail slash hitboxes --- HKMP/Animation/Effects/CycloneSlash.cs | 15 ++++++-- HKMP/Animation/Effects/DashSlash.cs | 47 +++++++++++++---------- HKMP/Animation/Effects/GreatSlash.cs | 13 +++++-- HKMP/Animation/Effects/ParryableEffect.cs | 16 ++++++++ HKMP/Animation/Effects/SlashBase.cs | 46 +++++++++++++++++----- HKMP/Api/Server/IServerSettings.cs | 5 +++ HKMP/Game/Settings/ServerSettings.cs | 3 ++ HKMP/HkmpMod.cs | 19 ++++++++- 8 files changed, 125 insertions(+), 39 deletions(-) create mode 100644 HKMP/Animation/Effects/ParryableEffect.cs diff --git a/HKMP/Animation/Effects/CycloneSlash.cs b/HKMP/Animation/Effects/CycloneSlash.cs index 80ced94b..6e9e5e90 100644 --- a/HKMP/Animation/Effects/CycloneSlash.cs +++ b/HKMP/Animation/Effects/CycloneSlash.cs @@ -7,7 +7,7 @@ namespace Hkmp.Animation.Effects; /// /// Animation effect class for the Cyclone Slash ability. /// -internal class CycloneSlash : DamageAnimationEffect { +internal class CycloneSlash : ParryableEffect { /// public override void Play(GameObject playerObject, bool[] effectInfo) { // Cancel the nail art charge animation if it exists @@ -54,9 +54,16 @@ public override void Play(GameObject playerObject, bool[] effectInfo) { cycloneSlash.LocateMyFSM("Control Collider").SetState("Init"); var damage = ServerSettings.CycloneSlashDamage; - if (ServerSettings.IsPvpEnabled && ShouldDoDamage && damage != 0) { - hitLComponent.AddComponent().damageDealt = damage; - hitRComponent.AddComponent().damageDealt = damage; + if (ServerSettings.IsPvpEnabled) { + if (ServerSettings.AllowParries) { + var fsm = cycloneSlash.AddComponent(); + fsm.SetFsmTemplate(NailClashTink.FsmTemplate); + } + + if (ShouldDoDamage && damage != 0) { + hitLComponent.AddComponent().damageDealt = damage; + hitRComponent.AddComponent().damageDealt = damage; + } } // As a failsafe, destroy the cyclone slash after 4 seconds diff --git a/HKMP/Animation/Effects/DashSlash.cs b/HKMP/Animation/Effects/DashSlash.cs index 794e4d14..a23cae68 100644 --- a/HKMP/Animation/Effects/DashSlash.cs +++ b/HKMP/Animation/Effects/DashSlash.cs @@ -7,7 +7,7 @@ namespace Hkmp.Animation.Effects; /// /// Animation effect class for the Dash Slash ability. /// -internal class DashSlash : DamageAnimationEffect { +internal class DashSlash : ParryableEffect { /// public override void Play(GameObject playerObject, bool[] effectInfo) { // Cancel the nail art charge animation if it exists @@ -61,25 +61,32 @@ public override void Play(GameObject playerObject, bool[] effectInfo) { dashSlash.LocateMyFSM("Control Collider").SetState("Init"); var damage = ServerSettings.DashSlashDamage; - if (ServerSettings.IsPvpEnabled && ShouldDoDamage && damage != 0) { - // Somehow adding a DamageHero component simply to the dash slash object doesn't work, - // so we create a separate object for it - var dashSlashCollider = Object.Instantiate( - new GameObject( - "DashSlashCollider", - typeof(PolygonCollider2D), - typeof(DamageHero) - ), - dashSlash.transform - ); - dashSlashCollider.SetActive(true); - dashSlashCollider.layer = 22; - - // Copy over the polygon collider points - dashSlashCollider.GetComponent().points = - dashSlash.GetComponent().points; - - dashSlashCollider.GetComponent().damageDealt = damage; + if (ServerSettings.IsPvpEnabled) { + if (ServerSettings.AllowParries) { + var fsm = dashSlash.AddComponent(); + fsm.SetFsmTemplate(NailClashTink.FsmTemplate); + } + + if (ShouldDoDamage && damage != 0) { + // Somehow adding a DamageHero component simply to the dash slash object doesn't work, + // so we create a separate object for it + var dashSlashCollider = Object.Instantiate( + new GameObject( + "DashSlashCollider", + typeof(PolygonCollider2D), + typeof(DamageHero) + ), + dashSlash.transform + ); + dashSlashCollider.SetActive(true); + dashSlashCollider.layer = 22; + + // Copy over the polygon collider points + dashSlashCollider.GetComponent().points = + dashSlash.GetComponent().points; + + dashSlashCollider.GetComponent().damageDealt = damage; + } } // Get the animator, figure out the duration of the animation and destroy the object accordingly afterwards diff --git a/HKMP/Animation/Effects/GreatSlash.cs b/HKMP/Animation/Effects/GreatSlash.cs index 1e2fc5d2..cd813582 100644 --- a/HKMP/Animation/Effects/GreatSlash.cs +++ b/HKMP/Animation/Effects/GreatSlash.cs @@ -7,7 +7,7 @@ namespace Hkmp.Animation.Effects; /// /// Animation effect class for the Great Slash ability. /// -internal class GreatSlash : DamageAnimationEffect { +internal class GreatSlash : ParryableEffect { /// public override void Play(GameObject playerObject, bool[] effectInfo) { // Cancel the nail art charge animation if it exists @@ -47,8 +47,15 @@ public override void Play(GameObject playerObject, bool[] effectInfo) { greatSlash.LocateMyFSM("Control Collider").SetState("Init"); var damage = ServerSettings.GreatSlashDamage; - if (ServerSettings.IsPvpEnabled && ShouldDoDamage && damage != 0) { - greatSlash.AddComponent().damageDealt = damage; + if (ServerSettings.IsPvpEnabled) { + if (ServerSettings.AllowParries) { + var fsm = greatSlash.AddComponent(); + fsm.SetFsmTemplate(NailClashTink.FsmTemplate); + } + + if (ShouldDoDamage && damage != 0) { + greatSlash.AddComponent().damageDealt = damage; + } } // Get the animator, figure out the duration of the animation and destroy the object accordingly afterwards diff --git a/HKMP/Animation/Effects/ParryableEffect.cs b/HKMP/Animation/Effects/ParryableEffect.cs new file mode 100644 index 00000000..c5e4846d --- /dev/null +++ b/HKMP/Animation/Effects/ParryableEffect.cs @@ -0,0 +1,16 @@ +namespace Hkmp.Animation.Effects; + +/// +/// Represents an animation effect that can be parried, such as nail slashes or nail arts. +/// +internal abstract class ParryableEffect : DamageAnimationEffect { + /// + /// The FSM for the nail parry effect. + /// + protected readonly PlayMakerFSM NailClashTink; + + protected ParryableEffect() { + var hiveKnightSlash = HkmpMod.PreloadedObjects["Hive_05"]["Battle Scene/Hive Knight/Slash 1"]; + NailClashTink = hiveKnightSlash.GetComponent(); + } +} diff --git a/HKMP/Animation/Effects/SlashBase.cs b/HKMP/Animation/Effects/SlashBase.cs index b4d36e76..168ea438 100644 --- a/HKMP/Animation/Effects/SlashBase.cs +++ b/HKMP/Animation/Effects/SlashBase.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Hkmp.Util; using HutongGames.PlayMaker.Actions; using UnityEngine; @@ -7,7 +8,18 @@ namespace Hkmp.Animation.Effects; /// /// Abstract base class for the animation effect of nail slashes. /// -internal abstract class SlashBase : DamageAnimationEffect { +internal abstract class SlashBase : ParryableEffect { + /// + /// Base X and Y scales for the various slash types. + /// + private static readonly Dictionary _baseScales = new() { + { SlashType.Normal, new Vector2(1.6011f, 1.6452f) }, + { SlashType.Alt, new Vector2(1.257f, 1.4224f) }, + { SlashType.Down, new Vector2(1.125f, 1.28f) }, + { SlashType.Up, new Vector2(1.15f, 1.4f) }, + { SlashType.Wall, new Vector2(1.62f, 1.6452f) } + }; + /// public abstract override void Play(GameObject playerObject, bool[] effectInfo); @@ -47,6 +59,16 @@ protected void Play(GameObject playerObject, bool[] effectInfo, GameObject prefa // Instantiate the slash gameObject from the given prefab // and use the attack gameObject as transform reference var slash = Object.Instantiate(prefab, playerAttacks.transform); + + // Set the base scale of the slash based on the slash type, this prevents remote nail slashes to occur + // larger than they should be if they are based on the prefab from Long Nail/Mark of Pride/both slash + var baseScale = _baseScales[type]; + slash.transform.localScale = new Vector3( + baseScale.x, + baseScale.y, + 0f + ); + // Get the NailSlash component and destroy it, since we don't want to interfere with the local player var originalNailSlash = slash.GetComponent(); Object.Destroy(originalNailSlash); @@ -83,16 +105,12 @@ protected void Play(GameObject playerObject, bool[] effectInfo, GameObject prefa // Scale the nail slash based on Long nail and Mark of pride charms if (hasLongNailCharm) { if (hasMarkOfPrideCharm) { - slash.transform.localScale = new Vector3(scale.x * 1.4f, scale.y * 1.4f, - scale.z); + slash.transform.localScale = new Vector3(scale.x * 1.4f, scale.y * 1.4f, scale.z); } else { - slash.transform.localScale = new Vector3(scale.x * 1.25f, - scale.y * 1.25f, - scale.z); + slash.transform.localScale = new Vector3(scale.x * 1.15f, scale.y * 1.15f, scale.z); } } else if (hasMarkOfPrideCharm) { - slash.transform.localScale = new Vector3(scale.x * 1.15f, scale.y * 1.15f, - scale.z); + slash.transform.localScale = new Vector3(scale.x * 1.25f, scale.y * 1.25f, scale.z); } } @@ -133,9 +151,17 @@ protected void Play(GameObject playerObject, bool[] effectInfo, GameObject prefa polygonCollider.enabled = true; var damage = ServerSettings.NailDamage; - if (ServerSettings.IsPvpEnabled && ShouldDoDamage && damage != 0) { + if (ServerSettings.IsPvpEnabled) { // TODO: make it possible to pogo on players - slash.AddComponent().damageDealt = damage; + + if (ServerSettings.AllowParries) { + var fsm = slash.AddComponent(); + fsm.SetFsmTemplate(NailClashTink.FsmTemplate); + } + + if (ShouldDoDamage && damage != 0) { + slash.AddComponent().damageDealt = damage; + } } // After the animation is finished, we can destroy the slash object diff --git a/HKMP/Api/Server/IServerSettings.cs b/HKMP/Api/Server/IServerSettings.cs index 58ccda19..5b4ea343 100644 --- a/HKMP/Api/Server/IServerSettings.cs +++ b/HKMP/Api/Server/IServerSettings.cs @@ -39,6 +39,11 @@ public interface IServerSettings { /// Whether skins are allowed. /// public bool AllowSkins { get; } + + /// + /// Whether other player's attacks can be parried. + /// + public bool AllowParries { get; } /// /// The damage that nail swings from other players deal to the local player. diff --git a/HKMP/Game/Settings/ServerSettings.cs b/HKMP/Game/Settings/ServerSettings.cs index 78c609fa..6fbe134a 100644 --- a/HKMP/Game/Settings/ServerSettings.cs +++ b/HKMP/Game/Settings/ServerSettings.cs @@ -28,6 +28,9 @@ public class ServerSettings : IServerSettings, IEquatable { /// public bool AllowSkins { get; set; } = true; + /// + public bool AllowParries { get; set; } = true; + /// public byte NailDamage { get; set; } = 1; diff --git a/HKMP/HkmpMod.cs b/HKMP/HkmpMod.cs index be869235..d0820165 100644 --- a/HKMP/HkmpMod.cs +++ b/HKMP/HkmpMod.cs @@ -1,4 +1,5 @@ -using Hkmp.Game.Settings; +using System.Collections.Generic; +using Hkmp.Game.Settings; using Hkmp.Logging; using Hkmp.Util; using Modding; @@ -11,6 +12,11 @@ namespace Hkmp; /// Mod class for the HKMP mod. /// internal class HkmpMod : Mod, IGlobalSettings { + /// + /// Dictionary containing preloaded objects by scene name and object path. + /// + public static Dictionary> PreloadedObjects; + /// /// Statically create Settings object, so it can be accessed early. /// @@ -28,7 +34,16 @@ public override string GetVersion() { } /// - public override void Initialize() { + public override List<(string, string)> GetPreloadNames() { + return new List<(string, string)> { + ("Hive_05", "Battle Scene/Hive Knight/Slash 1") + }; + } + + /// + public override void Initialize(Dictionary> preloadedObjects) { + PreloadedObjects = preloadedObjects; + // Add the logger that logs to the ModLog Logger.AddLogger(new ModLogger());