From 9163a96b99fde5103055873c7560a0260c9fc0dd Mon Sep 17 00:00:00 2001 From: Mirsario Date: Thu, 26 Sep 2024 17:10:23 +0300 Subject: [PATCH] Refactored grappling hooks to store stats in a less hardcoded manner. --- CHANGELOG.md | 1 + Common/GrapplingHooks/GrapplingHookStats.cs | 155 ++++++++++++++++++ .../ProjectileGrapplingHookPhysics.cs | 72 +------- 3 files changed, 159 insertions(+), 69 deletions(-) create mode 100644 Common/GrapplingHooks/GrapplingHookStats.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 653c73c0..c98ac4df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ - For English, changed `Expert`'s difficulty level rename to `Turn Me Undead`. For obvious reasons. - Removed all unused and functionless legacy content from compilation: `Charcoal`, `Calendars`, `Gramophones`, `Stone Axes`, `Stone Pickaxes`, `Ash Clots`, `Walking Ashes`. These bits will be reintroduced when required. - Wall flips and wall rolls were made slightly more reliable, with their code rewritten. +- Grappling hooks' code was made more data-driven, with some vanilla hook range values corrected. ### Configuration - Existing features received the following new options: **Guns:** `EnableMinigunDynamicFirerate`, `EnableStarCannonDynamicFirerate`. diff --git a/Common/GrapplingHooks/GrapplingHookStats.cs b/Common/GrapplingHooks/GrapplingHookStats.cs new file mode 100644 index 00000000..b08ac56a --- /dev/null +++ b/Common/GrapplingHooks/GrapplingHookStats.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using Terraria; +using Terraria.ID; +using Terraria.ModLoader; +using TerrariaOverhaul.Core.Debugging; + +namespace TerrariaOverhaul.Common.GrapplingHooks; + +public struct GrapplingHookStats +{ + private static readonly Dictionary stats = []; + private static readonly HashSet grapplingTypesWarnedAbout = []; + + public float Range = 300f; + public float PullSpeed = 12.5f; + public float PullVelocity = 0.1f; + public float RaiseSpeed = 5.0f; + public float RaiseVelocity = 0.975f; + public float LowerSpeed = 5.0f; + public float LowerVelocity = 1.0f; + + public GrapplingHookStats() { } + + public static GrapplingHookStats Get(Player player, Projectile projectile) + { + if (projectile.type <= 0) { + throw new IndexOutOfRangeException($"{projectile.type} <= 0"); + } + + if (stats.TryGetValue(projectile.type, out var result)) { + return result; + } + + if (projectile.type < ProjectileID.Count || projectile.ModProjectile is not ModProjectile modProjectile) { + if (grapplingTypesWarnedAbout.Add(projectile.type)) { + DebugSystem.Logger.Warn($"Vanilla grappling hook '{ContentSamples.ProjectilesByType[projectile.type].Name}' (ID: {projectile.type}) does not have stats assigned."); + } + + return new(); + } + + result = new() { + Range = modProjectile.GrappleRange(), + }; + + ProjectileLoader.GrapplePullSpeed(projectile, player, ref result.PullSpeed); + + return result; + } + + public static void Set(int projectileType, GrapplingHookStats value) + => stats[projectileType] = value; + + static GrapplingHookStats() + { + // PHM Singlehooks + Set(ProjectileID.Hook, new() { + Range = 300f, + }); + Set(ProjectileID.SquirrelHook, new() { + Range = 300f, + }); + Set(ProjectileID.GemHookAmethyst, new() { + Range = 300f, + }); + Set(ProjectileID.GemHookTopaz, new() { + Range = 330f, + }); + Set(ProjectileID.GemHookSapphire, new() { + Range = 360f, + }); + Set(ProjectileID.GemHookEmerald, new() { + Range = 390f, + }); + Set(ProjectileID.GemHookRuby, new() { + Range = 420f, + }); + Set(ProjectileID.AmberHook, new() { + Range = 420f, + }); + Set(ProjectileID.GemHookDiamond, new() { + Range = 466f, + }); + // PHM Multihooks + Set(ProjectileID.Web, new() { + Range = 375f, + }); + Set(ProjectileID.SkeletronHand, new() { + Range = 350f, + }); + Set(ProjectileID.SlimeHook, new() { + Range = 300f, + }); + Set(ProjectileID.FishHook, new() { + Range = 400f, + }); + Set(ProjectileID.IvyWhip, new() { + Range = 400f, + }); + Set(ProjectileID.BatHook, new() { + Range = 500f, + }); + Set(ProjectileID.CandyCaneHook, new() { + Range = 400f, + }); + // HM Singlehooks + Set(ProjectileID.DualHookBlue, new() { + Range = 440f, + }); + Set(ProjectileID.DualHookRed, new() { + Range = 440f, + }); + Set(ProjectileID.QueenSlimeHook, new() { + Range = 500f, + }); + Set(ProjectileID.StaticHook, new() { + Range = 600f, + }); + // HM Multihooks + Set(ProjectileID.TendonHook, new() { + Range = 480f, + }); + Set(ProjectileID.ThornHook, new() { + Range = 480f, + }); + Set(ProjectileID.IlluminantHook, new() { + Range = 480f, + }); + Set(ProjectileID.WormHook, new() { + Range = 480f, + }); + Set(ProjectileID.AntiGravityHook, new() { + Range = 500f, + }); + Set(ProjectileID.WoodHook, new() { + Range = 550f, + }); + Set(ProjectileID.ChristmasHook, new() { + Range = 550f, + }); + Set(ProjectileID.LunarHookSolar, new() { + Range = 550f, + }); + Set(ProjectileID.LunarHookVortex, new() { + Range = 550f, + }); + Set(ProjectileID.LunarHookNebula, new() { + Range = 550f, + }); + Set(ProjectileID.LunarHookStardust, new() { + Range = 550f, + }); + } +} diff --git a/Common/GrapplingHooks/ProjectileGrapplingHookPhysics.cs b/Common/GrapplingHooks/ProjectileGrapplingHookPhysics.cs index f1893bc7..4997c75e 100644 --- a/Common/GrapplingHooks/ProjectileGrapplingHookPhysics.cs +++ b/Common/GrapplingHooks/ProjectileGrapplingHookPhysics.cs @@ -22,9 +22,6 @@ public class ProjectileGrapplingHookPhysics : GlobalProjectile public const int GrapplingHookAIStyle = ProjAIStyleID.Hook; - private static HashSet? grapplingTypesWarnedAbout; - private static Dictionary? vanillaHookRangesInPixels; - private float maxDist; private bool noPulling; @@ -59,76 +56,13 @@ public override void Load() physics.ProjectileGrappleMovement(player, projectile); }; - - // Vanilla's data for this is hardcoded and not accessible. These stats are from the wiki. - vanillaHookRangesInPixels = new Dictionary { - // PHM Singlehooks - { ProjectileID.Hook, 300f }, // ID 13 - { ProjectileID.SquirrelHook, 300f }, // ID 865 - { ProjectileID.GemHookAmethyst, 300f }, // ID 230 - { ProjectileID.GemHookTopaz, 330f }, // ID 231 - { ProjectileID.GemHookSapphire, 360f }, // ID 232 - { ProjectileID.GemHookEmerald, 390f }, // ID 233 - { ProjectileID.GemHookRuby, 420f }, // ID 234 - { ProjectileID.AmberHook, 420f }, // ID 753 - { ProjectileID.GemHookDiamond, 466f }, // ID 235 - // PHM Multihooks - { ProjectileID.Web, 375f }, // ID 165 - { ProjectileID.SkeletronHand, 350f }, // ID 256 - { ProjectileID.SlimeHook, 300f }, // ID 396 - { ProjectileID.FishHook, 400f }, // ID 372 - { ProjectileID.IvyWhip, 400f }, // ID 32 - { ProjectileID.BatHook, 500f }, // ID 315 - { ProjectileID.CandyCaneHook, 400f }, // ID 331 - // HM Singlehooks - { ProjectileID.DualHookBlue, 440f }, // ID 73 - { ProjectileID.DualHookRed, 440f }, // ID 74 - { ProjectileID.QueenSlimeHook, 500f }, // ID 935 - { ProjectileID.StaticHook, 600f }, // ID 652 - // HM Multihooks - { ProjectileID.TendonHook, 480f }, // ID 486 - { ProjectileID.ThornHook, 480f }, // ID 487 - { ProjectileID.IlluminantHook, 480f }, // ID 488 - { ProjectileID.WormHook, 480f }, // ID 489 - { ProjectileID.AntiGravityHook, 500f }, // ID 446 - { ProjectileID.WoodHook, 550f }, // ID 322 - { ProjectileID.ChristmasHook, 550f }, // ID 332 - { ProjectileID.LunarHookSolar, 550f }, // ID 646 - { ProjectileID.LunarHookVortex, 550f }, // ID 647 - { ProjectileID.LunarHookNebula, 550f }, // ID 648 - { ProjectileID.LunarHookStardust, 550f }, // ID 649 - }; - } - - public override void Unload() - { - if (vanillaHookRangesInPixels != null) { - vanillaHookRangesInPixels.Clear(); - - vanillaHookRangesInPixels = null; - } } public void ProjectileGrappleMovement(Player player, Projectile proj) { - if (vanillaHookRangesInPixels == null) { - throw new InvalidOperationException($"'{nameof(ProjectileGrappleMovement)}' called before '{nameof(Load)}'."); - } - var playerCenter = player.Center; var projCenter = proj.Center; - float hookRange; - - if (proj.ModProjectile != null) { - hookRange = proj.ModProjectile.GrappleRange(); - } else if (!vanillaHookRangesInPixels.TryGetValue(proj.type, out hookRange)) { - // Fallback, not intended to be ran. - hookRange = 512f; - - if ((grapplingTypesWarnedAbout ??= new()).Add(proj.type)) { - DebugSystem.Logger.Warn($"Vanilla grappling hook '{proj.Name}' (ID: {proj.type}) does not have a hook range assigned. Please report this."); - } - } + var hookStats = GrapplingHookStats.Get(player, proj); var mountedCenter = player.MountedCenter; var mountedOffset = mountedCenter - projCenter; @@ -149,10 +83,10 @@ public void ProjectileGrappleMovement(Player player, Projectile proj) // Prevent hooks from going farther than normal float ClampDistance(float distance) - => MathHelper.Clamp(distance, 0f, hookRange - 1f); + => MathHelper.Clamp(distance, 0f, hookStats.Range - 1f); float dist = ClampDistance(Vector2.Distance(playerCenter, projCenter)); - bool down = player.controlDown && maxDist < hookRange; + bool down = player.controlDown && maxDist < hookStats.Range; bool up = player.controlUp; const float PullSpeed = 12.5f;