From 0d30d2673b26041b6054be3a8e99e091d8102b9d Mon Sep 17 00:00:00 2001 From: wuke32767 <2446214230@qq.com> Date: Fri, 15 Nov 2024 19:16:51 +0800 Subject: [PATCH] finished? --- Source/Entities/LockBlocks/BaseLockBlock.cs | 10 +- Source/Entities/LockBlocks/DreamLockBlock.cs | 23 +- .../Entities/LockBlocks/DreamLockBlockV2.cs | 235 ++++++++++++++++++ Source/MoreLockBlocksModule.cs | 2 + 4 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 Source/Entities/LockBlocks/DreamLockBlockV2.cs diff --git a/Source/Entities/LockBlocks/BaseLockBlock.cs b/Source/Entities/LockBlocks/BaseLockBlock.cs index f418ed7..9c3cdb4 100644 --- a/Source/Entities/LockBlocks/BaseLockBlock.cs +++ b/Source/Entities/LockBlocks/BaseLockBlock.cs @@ -55,6 +55,8 @@ public struct OpeningSettings protected internal readonly string unlockSfxName; + private PlayerCollider playerCollider; + public BaseLockBlockComponent(Solid This, EntityData data, Vector2 offset, EntityID id, string defaultSpriteID = "MoreLockBlocks_generic_lock", string defaultUnlockSfx = "event:/game/03_resort/key_unlock") //: base(data.Position + offset, 32f, 32f, false) : base(true, true) @@ -77,7 +79,7 @@ public BaseLockBlockComponent(Solid This, EntityData data, Vector2 offset, Entit ID = id; RealEntity.DisableLightsInside = false; - RealEntity.Add(new PlayerCollider(OnPlayer, new Circle(60f, 16f, 16f))); + RealEntity.Add(playerCollider = new PlayerCollider(OnPlayer, new Circle(60f, 16f, 16f))); RealEntity.Add(Sprite = string.IsNullOrWhiteSpace(overrideSpritePath = data.Attr("spritePath", "")) ? MoreLockBlocksGFX.SpriteBank.Create(defaultSpriteID) : BuildCustomSprite(overrideSpritePath)); Sprite.Play("idle"); @@ -299,6 +301,12 @@ protected internal virtual IEnumerator default_UnlockRoutine_DzhakeHelperUnloade RealEntity.RemoveSelf(); } + internal void Remove() + { + playerCollider.RemoveSelf(); + Sprite.RemoveSelf(); + } + #endregion } } \ No newline at end of file diff --git a/Source/Entities/LockBlocks/DreamLockBlock.cs b/Source/Entities/LockBlocks/DreamLockBlock.cs index 5105546..f3f5cd8 100644 --- a/Source/Entities/LockBlocks/DreamLockBlock.cs +++ b/Source/Entities/LockBlocks/DreamLockBlock.cs @@ -16,9 +16,20 @@ namespace Celeste.Mod.MoreLockBlocks.Entities { [Tracked] - [CustomEntity("MoreLockBlocks/DreamLockBlock")] + [CustomEntity("MoreLockBlocks/DreamLockBlock=Load")] public class DreamLockBlock : LegacyBaseLockBlock { + public static Entity Load(Level level, LevelData levelData, Vector2 offset, EntityData entityData) + { + if (MoreLockBlocksModule.PatchLoaded) + { + return new DreamLockBlockV2(entityData, offset, new EntityID(levelData.Name, entityData.ID)); + } + else + { + return new DreamLockBlock(entityData, offset, new EntityID(levelData.Name, entityData.ID)); + } + } [TrackedAs(typeof(DreamBlock))] internal class DreamBlockDummy : DreamBlock { @@ -121,6 +132,11 @@ public IEnumerator DummyUnlockRoutine() public static void Load() { + if (MoreLockBlocksModule.PatchLoaded) + { + DreamLockBlockV2.Load(); + return; + } IL.Celeste.DreamBlock.Added += DreamBlock_Added; On.Celeste.DreamBlock.Activate += DreamBlock_Activate; On.Celeste.DreamBlock.FastActivate += DreamBlock_FastActivate; @@ -139,6 +155,11 @@ public static void Load() public static void Unload() { + if (MoreLockBlocksModule.PatchLoaded) + { + DreamLockBlockV2.Unload(); + return; + } IL.Celeste.DreamBlock.Added -= DreamBlock_Added; On.Celeste.DreamBlock.Activate -= DreamBlock_Activate; On.Celeste.DreamBlock.FastActivate -= DreamBlock_FastActivate; diff --git a/Source/Entities/LockBlocks/DreamLockBlockV2.cs b/Source/Entities/LockBlocks/DreamLockBlockV2.cs new file mode 100644 index 0000000..a0a7982 --- /dev/null +++ b/Source/Entities/LockBlocks/DreamLockBlockV2.cs @@ -0,0 +1,235 @@ +using Celeste.Mod.DzhakeHelper; +using Celeste.Mod.DzhakeHelper.Entities; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using MonoMod; +using MonoMod.RuntimeDetour; +using System; +using System.Collections; + +namespace Celeste.Mod.MoreLockBlocks.Entities +{ + [CustomEntity("MoreLockBlocks/DreamLockBlock")] + [TrackedAs(typeof(DreamBlock))] + internal class DreamLockBlockV2 : DreamBlock + { + readonly bool ignoreInventory; + BaseLockBlockComponent component; + bool unlocked; + public DreamLockBlockV2(EntityData data, Vector2 offset, EntityID id) + : base(data.Position + offset, 32, 32, null, false, false, data.Bool("below", false)) + // : base(data, offset, id, defaultUnlockSfx: MoreLockBlocksSFX.game_lockblocks_dreamlockblock_key_unlock) + { + Add(component = new BaseLockBlockComponent(this, data, offset, id, defaultUnlockSfx: MoreLockBlocksSFX.game_lockblocks_dreamlockblock_key_unlock)); + SurfaceSoundIndex = 11; + ignoreInventory = data.Bool("ignoreInventory", false); + if (MoreLockBlocksModule.Instance.DzhakeHelperLoaded) + { + component.UnlockRoutine = UnlockRoutine_DzhakeHelperLoaded; + } + else + { + component.UnlockRoutine = UnlockRoutine_DzhakeHelperUnloaded; + } + } + public override void Added(Scene scene) + { + if (MoreLockBlocksModule.Session.UnlockedDreamLockBlocks.Contains(component.ID)) + { + unlocked = true; + component.Remove(); + } + base.Added(scene); + } + public override void Render() + { + base.Render(); + //:sobeline: + Entity_Render(this); + } + [MonoModLinkTo("Monocle.Entity", "System.Void Render()")] + private static void Entity_Render(Entity self) + { + throw new NotImplementedException(); + } + + private const float chargeUpDuration = 6f, unlockDuration = 0.25f, chargeDownDuration = 0.1f; + + public IEnumerator DummyUnlockRoutine() + { + if (!Activated) + { + yield break; + } + Level level = SceneAs(); + Input.Rumble(RumbleStrength.Light, RumbleLength.Long); + Add(shaker = new Shaker(true, delegate (Vector2 s) + { + shake = s; + })); + shaker.Interval = 0.02f; + + for (float percent = 0f; percent < 1f; percent += Engine.DeltaTime / chargeUpDuration) + { + whiteFill = Ease.CubeIn(percent); + yield return null; + } + UpdateNoRoutine(); // in some cases, this will not be called. + shaker.On = false; // so better to close it manually. + + whiteHeight = 1f; + whiteFill = 1f; + for (float percent = 1f; percent > 0f; percent -= Engine.DeltaTime / unlockDuration) + { + whiteHeight = percent; + Glitch.Value = percent * 0.2f; + if (level.OnInterval(0.1f)) + { + for (int i = 0; i < Width; i += 4) + { + level.ParticlesFG.Emit(Strawberry.P_WingsBurst, new Vector2(X + i, Y + Height * whiteHeight + 1f)); + } + } + if (level.OnInterval(0.1f)) + { + level.Shake(); + } + Input.Rumble(RumbleStrength.Strong, RumbleLength.Short); + yield return null; + } + whiteHeight = Glitch.Value = 0f; + + while (whiteFill > 0f) + { + whiteFill -= Engine.DeltaTime / chargeDownDuration; + yield return null; + } + } + + IEnumerator UnlockRoutine_DzhakeHelperLoaded(Follower fol) + { + SoundEmitter emitter = SoundEmitter.Play(component.unlockSfxName, this); + emitter.Source.DisposeOnTransition = true; + Level level = SceneAs(); + + Key key = fol.Entity as Key; + CustomKey key2 = fol.Entity as CustomKey; + if (key is not null) + { + Add(new Coroutine(key.UseRoutine(Center + new Vector2(0f, 2f)))); + } + else if (key2 is not null) + { + Add(new Coroutine(key2.UseRoutine(Center + new Vector2(0f, 2f)))); + } + yield return 1.2f; + + component.UnlockingRegistered = true; + if (component.stepMusicProgress) + { + level.Session.Audio.Music.Progress++; + level.Session.Audio.Apply(); + } + MoreLockBlocksModule.Session.UnlockedDreamLockBlocks.Add(component.ID); + if (key is not null) + { + key.RegisterUsed(); + + while (key.Turning) + { + yield return null; + } + } + else if (key2 is not null) + { + key2.RegisterUsed(); + DzhakeHelperModule.Session.CurrentKeys.RemoveAll(info => info.ID.ID == key2.ID.ID); + + while (key2.Turning) + { + yield return null; + } + } + + Tag |= Tags.TransitionUpdate; + //Collidable = false; + unlocked = true; + emitter.Source.DisposeOnTransition = false; + Add(new Coroutine(DummyUnlockRoutine())); + SurfaceSoundIndex = 12; + yield return component.Sprite.PlayRoutine("open"); + + level.Shake(); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + yield return component.Sprite.PlayRoutine("burst"); + + } + + IEnumerator UnlockRoutine_DzhakeHelperUnloaded(Follower fol) + { + SoundEmitter emitter = SoundEmitter.Play(component.unlockSfxName, this); + emitter.Source.DisposeOnTransition = true; + Level level = SceneAs(); + + Key key = fol.Entity as Key; + Add(new Coroutine(key.UseRoutine(Center + new Vector2(0f, 2f)))); + yield return 1.2f; + + component.UnlockingRegistered = true; + if (component.stepMusicProgress) + { + level.Session.Audio.Music.Progress++; + level.Session.Audio.Apply(); + } + MoreLockBlocksModule.Session.UnlockedDreamLockBlocks.Add(component.ID); + key.RegisterUsed(); + while (key.Turning) + { + yield return null; + } + + Tag |= Tags.TransitionUpdate; + //Collidable = false; + unlocked = true; + emitter.Source.DisposeOnTransition = false; + Add(new Coroutine(DummyUnlockRoutine())); + SurfaceSoundIndex = 12; + yield return component.Sprite.PlayRoutine("open"); + + level.Shake(); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + yield return component.Sprite.PlayRoutine("burst"); + } + static Hook patch; + internal static void Load() + { + patch = new Hook(typeof(DreamBlock).GetProperty(nameof(DreamBlock.Activated)).GetMethod, static (Func orig, DreamBlock self) => + { + bool o = orig(self); + if (self is DreamLockBlockV2 v2) + { + if (!v2.unlocked) + { + return false; + } + if (v2.ignoreInventory) + { + return v2.unlocked; + } + } + return o; + }); + + } + + internal static void Unload() + { + patch?.Dispose(); + } + } +} + + + + diff --git a/Source/MoreLockBlocksModule.cs b/Source/MoreLockBlocksModule.cs index 3ac43a0..234e335 100644 --- a/Source/MoreLockBlocksModule.cs +++ b/Source/MoreLockBlocksModule.cs @@ -9,6 +9,8 @@ namespace Celeste.Mod.MoreLockBlocks; public class MoreLockBlocksModule : EverestModule { + public static readonly bool PatchLoaded = typeof(DreamBlock).GetField("DreamBlockPatch", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) is not null; + public static MoreLockBlocksModule Instance { get; private set; } public override Type SettingsType => typeof(MoreLockBlocksModuleSettings);