diff --git a/Content/Guardian/GuardianShieldAnchor.cs b/Content/Guardian/GuardianShieldAnchor.cs index 1fd39772..4732f60d 100644 --- a/Content/Guardian/GuardianShieldAnchor.cs +++ b/Content/Guardian/GuardianShieldAnchor.cs @@ -30,7 +30,8 @@ public class GuardianShieldAnchor : OrchidModGuardianAnchor public float networkedRotation => Projectile.ai[2]; // ... - + public bool IsRotationLocked; + private float LockedRotation; public override void SafeSetDefaults() { Projectile.width = 20; @@ -108,6 +109,7 @@ public override void AI() } float addedDistance = 0f; + if (Projectile.ai[1] > 0f) { // Shield bash if (isSlamming == 0) @@ -142,9 +144,12 @@ public override void AI() if (Projectile.ai[1] <= 0f) { + guardianItem.SlamEnd(owner, Projectile); Projectile.ai[1] = 0f; isSlamming = 0; Projectile.friendly = false; + IsRotationLocked = false; + Projectile.netUpdate = true; } } @@ -245,13 +250,15 @@ public override void AI() { aimedLocation = Main.MouseWorld - owner.Center.Floor(); aimedLocation.Normalize(); + + aimedLocation = Vector2.UnitX.RotatedBy(IsRotationLocked ? LockedRotation : OrchidModGuardianShield.GetSnappedAngle(guardianItem, owner,aimedLocation.ToRotation())); Projectile.velocity = aimedLocation * float.Epsilon; aimedLocation *= (guardianItem.distance + addedDistance) * -1f; Projectile.rotation = aimedLocation.ToRotation(); if (guardianItem.shouldFlip) { - if (aimedLocation.X < 0) + if (aimedLocation.X < 0 || (isSlamming is 1 or 2 && IsRotationLocked && -Vector2.UnitX.RotatedBy(LockedRotation).X < 0)) { Projectile.spriteDirection = -1; } @@ -284,6 +291,12 @@ public override void AI() if (isSlamming == 1) // Slam() is called here so the projectile has the time to reposition properly before effects such as projectile spawns are called { isSlamming = 2; + if (guardianItem.lockSlamRotation) + { + IsRotationLocked = true; + LockedRotation = Projectile.rotation + MathHelper.Pi; + Projectile.netUpdate = true; + } guardianItem.Slam(owner, Projectile); guardian.GuardianCounterTime = 0; } diff --git a/Content/Guardian/OrchidModGuardianShield.cs b/Content/Guardian/OrchidModGuardianShield.cs index e0ea28ad..beb40eae 100644 --- a/Content/Guardian/OrchidModGuardianShield.cs +++ b/Content/Guardian/OrchidModGuardianShield.cs @@ -1,3 +1,4 @@ +using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using OrchidMod.Common; @@ -28,6 +29,8 @@ public virtual void SlamHitFirst(Player player, Projectile shield, NPC npc) { } public virtual void SlamHit(Player player, Projectile shield, NPC npc) { } /// Called on the first frame of a slam. public virtual void Slam(Player player, Projectile shield) { } + /// Called on the last frame of a slam. + public virtual void SlamEnd(Player player, Projectile shield) { } /// Called when an enemy collides with the shield during a block. Will be called once per frame per enemy colliding with it. public virtual void Push(Player player, Projectile shield, NPC npc) { } /// Called once per block when the first enemy or projectile is blocked. This is called after Push or Block, but before Block destroys the projectile. @@ -49,6 +52,23 @@ public virtual void BlockStart(Player player, Projectile shield) { } /// Causes the shield's held sprite to flip when facing right. public bool shouldFlip = false; public bool slamAutoReuse = true; + /// + /// If true, the shield will be rotated in discrete steps, instead of a single continuous circle. Defaults to false. + /// + public bool useDiscreteAim = false; + /// + /// The amount of steps per half-rotation that the shield will snap to, if useDiscreteAim is true. + ///
A value of 0 results in only a single possible angle, directly in front of the player. Otherwise, there will be twice as many snap points as this value. + ///
+ public int discreteAimIncrements; + /// + /// The angle, in pi/2 increments, that the base angle will be rotated by. + /// + public int discreteAimRotation; + /// + /// If true, slams performed with the shield will be locked to the rotation they started with, rather than being free to rotate mid-slam. + /// + public bool lockSlamRotation; public sealed override void SetDefaults() { @@ -61,6 +81,10 @@ public sealed override void SetDefaults() Item.useStyle = ItemUseStyleID.Thrust; Item.useTime = 30; Item.knockBack = 6f; + useDiscreteAim = false; + discreteAimIncrements = 2; + discreteAimRotation = 0; + lockSlamRotation = false; OrchidGlobalItemPerEntity orchidItem = Item.GetGlobalItem(); orchidItem.guardianWeapon = true; @@ -243,5 +267,17 @@ public override void ModifyTooltips(List tooltips) OverrideColor = new Color(175, 255, 175) }); } + + public static float GetSnappedAngle(OrchidModGuardianShield shield, Player player, float originalAngle) + { + if (!shield.useDiscreteAim) return originalAngle; + if (shield.discreteAimIncrements == 0) return -player.direction * MathHelper.PiOver2 * shield.discreteAimRotation + (player.direction == -1 ? MathHelper.Pi : 0f); + else + { + float angleIncrement = MathHelper.Pi / shield.discreteAimIncrements; + return (float)Math.Round((Vector2.Normalize(Main.MouseWorld - player.MountedCenter.Floor()).ToRotation() + MathHelper.PiOver2 * shield.discreteAimRotation) / angleIncrement) * angleIncrement - MathHelper.PiOver2 * shield.discreteAimRotation; + } + + } } }