|
| 1 | +using Celeste.Mod.Entities; |
| 2 | +using Microsoft.Xna.Framework; |
| 3 | +using Monocle; |
| 4 | +using System; |
| 5 | +using System.Reflection; |
| 6 | + |
| 7 | +namespace Celeste.Mod.SpringCollab2020.Entities { |
| 8 | + [CustomEntity("SpringCollab2020/MultiRoomStrawberrySeed")] |
| 9 | + class MultiRoomStrawberrySeed : StrawberrySeed { |
| 10 | + public static void Load() { |
| 11 | + On.Celeste.Level.LoadLevel += onLoadLevel; |
| 12 | + } |
| 13 | + |
| 14 | + public static void Unload() { |
| 15 | + On.Celeste.Level.LoadLevel -= onLoadLevel; |
| 16 | + } |
| 17 | + |
| 18 | + private static void onLoadLevel(On.Celeste.Level.orig_LoadLevel orig, Level self, Player.IntroTypes playerIntro, bool isFromLoader) { |
| 19 | + orig(self, playerIntro, isFromLoader); |
| 20 | + |
| 21 | + if (playerIntro != Player.IntroTypes.Transition) { |
| 22 | + Player player = self.Tracker.GetEntity<Player>(); |
| 23 | + |
| 24 | + if (player != null) { |
| 25 | + Vector2 seedPosition = player.Position; |
| 26 | + |
| 27 | + // we have to restore collected strawberry seeds. |
| 28 | + foreach (SpringCollab2020Session.MultiRoomStrawberrySeedInfo sessionSeedInfo in SpringCollab2020Module.Instance.Session.CollectedMultiRoomStrawberrySeeds) { |
| 29 | + seedPosition += new Vector2(-12 * (int) player.Facing, -8f); |
| 30 | + |
| 31 | + self.Add(new MultiRoomStrawberrySeed(player, seedPosition, sessionSeedInfo)); |
| 32 | + } |
| 33 | + } |
| 34 | + } |
| 35 | + } |
| 36 | + |
| 37 | + private static FieldInfo seedFollower = typeof(StrawberrySeed).GetField("follower", BindingFlags.NonPublic | BindingFlags.Instance); |
| 38 | + private static FieldInfo seedCanLoseTimer = typeof(StrawberrySeed).GetField("canLoseTimer", BindingFlags.NonPublic | BindingFlags.Instance); |
| 39 | + private static FieldInfo seedSprite = typeof(StrawberrySeed).GetField("sprite", BindingFlags.NonPublic | BindingFlags.Instance); |
| 40 | + |
| 41 | + private int index; |
| 42 | + public EntityID BerryID; |
| 43 | + |
| 44 | + private float canLoseTimerMirror; |
| 45 | + private Player player; |
| 46 | + private bool spawnedAsFollower = false; |
| 47 | + |
| 48 | + private string sprite; |
| 49 | + private bool ghost; |
| 50 | + |
| 51 | + public MultiRoomStrawberrySeed(Vector2 position, int index, bool ghost, string sprite, string ghostSprite) : base(null, position, index, ghost) { |
| 52 | + this.index = index; |
| 53 | + this.ghost = ghost; |
| 54 | + this.sprite = ghost ? ghostSprite : sprite; |
| 55 | + |
| 56 | + foreach (Component component in this) { |
| 57 | + if (component is PlayerCollider playerCollider) { |
| 58 | + playerCollider.OnCollide = OnPlayer; |
| 59 | + } |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + public MultiRoomStrawberrySeed(EntityData data, Vector2 offset) : this(data.Position + offset, data.Int("index"), |
| 64 | + SaveData.Instance.CheckStrawberry(new EntityID(data.Attr("berryLevel"), data.Int("berryID"))), |
| 65 | + data.Attr("sprite", "strawberry/seed"), data.Attr("ghostSprite", "ghostberry/seed")) { |
| 66 | + |
| 67 | + BerryID = new EntityID(data.Attr("berryLevel"), data.Int("berryID")); |
| 68 | + } |
| 69 | + |
| 70 | + private MultiRoomStrawberrySeed(Player player, Vector2 position, SpringCollab2020Session.MultiRoomStrawberrySeedInfo sessionSeedInfo) |
| 71 | + : this(position, sessionSeedInfo.Index, SaveData.Instance.CheckStrawberry(sessionSeedInfo.BerryID), sessionSeedInfo.Sprite, sessionSeedInfo.Sprite) { |
| 72 | + |
| 73 | + BerryID = sessionSeedInfo.BerryID; |
| 74 | + |
| 75 | + // the seed is collected right away. |
| 76 | + this.player = player; |
| 77 | + spawnedAsFollower = true; |
| 78 | + } |
| 79 | + |
| 80 | + public override void Added(Scene scene) { |
| 81 | + base.Added(scene); |
| 82 | + |
| 83 | + if (!spawnedAsFollower) { |
| 84 | + if (SceneAs<Level>().Session.GetFlag("collected_seeds_of_" + BerryID.ToString())) { |
| 85 | + // if all seeds for this berry were already collected (the berry was already formed), commit remove self. |
| 86 | + RemoveSelf(); |
| 87 | + } else { |
| 88 | + // if the seed already follows the player, commit remove self. |
| 89 | + foreach (SpringCollab2020Session.MultiRoomStrawberrySeedInfo sessionSeedInfo in SpringCollab2020Module.Instance.Session.CollectedMultiRoomStrawberrySeeds) { |
| 90 | + if (sessionSeedInfo.Index == index && sessionSeedInfo.BerryID.ID == BerryID.ID && sessionSeedInfo.BerryID.Level == BerryID.Level) { |
| 91 | + RemoveSelf(); |
| 92 | + break; |
| 93 | + } |
| 94 | + } |
| 95 | + } |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + public override void Awake(Scene scene) { |
| 100 | + base.Awake(scene); |
| 101 | + |
| 102 | + if ((ghost && sprite != "ghostberry/seed") || (!ghost && sprite != "strawberry/seed")) { |
| 103 | + // the sprite is non-default. replace it. |
| 104 | + Sprite vanillaSprite = (Sprite) seedSprite.GetValue(this); |
| 105 | + |
| 106 | + // build the new sprite. |
| 107 | + MTexture frame0 = GFX.Game["collectables/" + sprite + "00"]; |
| 108 | + MTexture frame1 = GFX.Game["collectables/" + sprite + "01"]; |
| 109 | + |
| 110 | + Sprite modSprite = new Sprite(GFX.Game, sprite); |
| 111 | + modSprite.CenterOrigin(); |
| 112 | + modSprite.Justify = new Vector2(0.5f, 0.5f); |
| 113 | + modSprite.AddLoop("idle", 0.1f, new MTexture[] { |
| 114 | + frame0, frame0, frame0, frame0, frame0, frame0, frame0, frame0, frame0, frame0, |
| 115 | + frame0, frame0, frame0, frame0, frame0, frame0, frame0, frame0, frame0, frame1 |
| 116 | + }); |
| 117 | + modSprite.AddLoop("noFlash", 0.1f, new MTexture[] { frame0 }); |
| 118 | + |
| 119 | + // copy over the values from the vanilla sprite |
| 120 | + modSprite.Position = vanillaSprite.Position; |
| 121 | + modSprite.Color = vanillaSprite.Color; |
| 122 | + modSprite.OnFrameChange = vanillaSprite.OnFrameChange; |
| 123 | + modSprite.Play("idle"); |
| 124 | + modSprite.SetAnimationFrame(vanillaSprite.CurrentAnimationFrame); |
| 125 | + |
| 126 | + // and replace it for good |
| 127 | + Remove(vanillaSprite); |
| 128 | + Add(modSprite); |
| 129 | + seedSprite.SetValue(this, modSprite); |
| 130 | + } |
| 131 | + |
| 132 | + if (spawnedAsFollower) { |
| 133 | + player.Leader.GainFollower((Follower) seedFollower.GetValue(this)); |
| 134 | + canLoseTimerMirror = 0.25f; |
| 135 | + Collidable = false; |
| 136 | + Depth = -1000000; |
| 137 | + AddTag(Tags.Persistent); |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + private void OnPlayer(Player player) { |
| 142 | + Audio.Play("event:/game/general/seed_touch", Position, "count", index); |
| 143 | + player.Leader.GainFollower((Follower) seedFollower.GetValue(this)); |
| 144 | + canLoseTimerMirror = 0.25f; |
| 145 | + Collidable = false; |
| 146 | + Depth = -1000000; |
| 147 | + AddTag(Tags.Persistent); |
| 148 | + |
| 149 | + // Add the info for this berry seed to the session. |
| 150 | + SpringCollab2020Session.MultiRoomStrawberrySeedInfo sessionSeedInfo = new SpringCollab2020Session.MultiRoomStrawberrySeedInfo(); |
| 151 | + sessionSeedInfo.Index = index; |
| 152 | + sessionSeedInfo.BerryID = BerryID; |
| 153 | + sessionSeedInfo.Sprite = sprite; |
| 154 | + SpringCollab2020Module.Instance.Session.CollectedMultiRoomStrawberrySeeds.Add(sessionSeedInfo); |
| 155 | + } |
| 156 | + |
| 157 | + public override void Update() { |
| 158 | + base.Update(); |
| 159 | + |
| 160 | + // be sure the canLoseTimer always has a positive value. we don't want the player to lose this berry seed. |
| 161 | + canLoseTimerMirror -= Engine.DeltaTime; |
| 162 | + if (canLoseTimerMirror < 1f) { |
| 163 | + canLoseTimerMirror = 1000f; |
| 164 | + seedCanLoseTimer.SetValue(this, 1000f); |
| 165 | + } |
| 166 | + } |
| 167 | + } |
| 168 | +} |
0 commit comments