private void GameSelectionPanel_RefreshContent(On.GameSelectionPanel.orig_RefreshContent orig, GameSelectionPanel self)
        {
            if (!run)
            {
                // Set GameConfig
                SetGameConfig();

                // Need to AT LEAST alter the following:
                // GameSelectionPanel.Display --> NullReference
                // Lift.Show() --> IndexOutOfBounds

                // GameSelectionPanel.Display --> NullReference
                var d = new DynData <GameSelectionPanel>(self);
                mod.Log("Before set:");
                mod.Log("GameSelectionPanel.maxHeroCount: " + d.Get <int>("maxHeroCount"));
                mod.Log("GameSelectionPanel.competitorsTable: " + d.Get <AgeTransform>("competitorsTable"));
                mod.Log("GameSelectionPanel.competitorSlots: " + d.Get <List <CompetitorSlot> >("competitorSlots"));

                d.Set <int>("maxHeroCount", maxHeroShipCountWrapper.Value);

                mod.Log("After set:");
                mod.Log("GameSelectionPanel.maxHeroCount: " + d.Get <int>("maxHeroCount"));


                run = true;
            }
            orig(self);
        }
예제 #2
0
        public override void Added(Scene scene)
        {
            base.Added(scene);
            Remove(baseData.Get <TileGrid>("tiles"));
            Remove(Get <TileInterceptor>());

            TileGrid tiles;

            if (baseData.Get <Modes>("mode") == Modes.Wall)
            {
                Level             level      = SceneAs <Level>();
                Rectangle         tileBounds = level.Session.MapData.TileBounds;
                VirtualMap <char> solidsData = level.SolidsData;
                int x = (int)X / 8 - tileBounds.Left;
                int y = (int)Y / 8 - tileBounds.Top;
                tiles = GFX.FGAutotiler.GenerateOverlay(tileMap, x, y, solidsData).TileGrid;
            }
            else
            {
                tiles = GFX.FGAutotiler.GenerateMap(tileMap, default(Autotiler.Behaviour)).TileGrid;
            }
            baseData["tiles"] = tiles;
            Add(baseData.Get <TileGrid>("tiles"));
            Add(new TileInterceptor(baseData.Get <TileGrid>("tiles"), false));
        }
        private void GameSelectionPanel_Display(On.GameSelectionPanel.orig_Display orig, GameSelectionPanel self, bool isMultiplayer, string mpSaveKey, int slotCount, GameSelectionPanel.GameSelectionFinishedHandler onGameSelectionFinished)
        {
            // Should happen often enough (before we get to the PodScreen) in order to work out.
            if (!run)
            {
                // Set GameConfig
                SetGameConfig();

                // Need to AT LEAST alter the following:
                // GameSelectionPanel.Display --> NullReference
                // Lift.Show() --> IndexOutOfBounds

                // GameSelectionPanel.Display --> NullReference
                var d = new DynData <GameSelectionPanel>(self);
                mod.Log("Before set:");
                mod.Log("GameSelectionPanel.maxHeroCount: " + d.Get <int>("maxHeroCount"));
                mod.Log("GameSelectionPanel.competitorsTable: " + d.Get <AgeTransform>("competitorsTable"));
                mod.Log("GameSelectionPanel.competitorSlots: " + d.Get <List <CompetitorSlot> >("competitorSlots"));

                d.Set <int>("maxHeroCount", maxHeroShipCountWrapper.Value);

                mod.Log("After set:");
                mod.Log("GameSelectionPanel.maxHeroCount: " + d.Get <int>("maxHeroCount"));

                run = true;
            }
            orig(self, isMultiplayer, mpSaveKey, slotCount, onGameSelectionFinished);
        }
예제 #4
0
        public override void Added(Scene scene)
        {
            // turn off createdFromLevel to prevent vanilla from spawning ReflectionTentacles.
            DynData <ReflectionTentacles> self = new DynData <ReflectionTentacles>(this);
            bool createdFromLevel = self.Get <bool>("createdFromLevel");

            self["createdFromLevel"] = false;

            // run vanilla code.
            base.Added(scene);

            // restore the createdFromLevel value.
            self["createdFromLevel"] = createdFromLevel;

            // add tentacles like vanilla would, but make them ForegroundReflectionTentacles.
            if (createdFromLevel)
            {
                for (int i = 1; i < 4; i++)
                {
                    ForegroundReflectionTentacles reflectionTentacles = new ForegroundReflectionTentacles();
                    reflectionTentacles.Create(self.Get <float>("fearDistance"), self.Get <int>("slideUntilIndex"), i, Nodes);
                    scene.Add(reflectionTentacles);
                }
            }

            // bring all tentacles to the foreground.
            Depth = -1000000 + self.Get <int>("layer");
        }
예제 #5
0
        private void FakeoutHeart(ILContext il)
        {
            var cursor = new ILCursor(il);

            if (!cursor.TryGotoNext(MoveType.After, instr => instr.MatchCallvirt <Player>("get_Dead")))
            {
                throw new Exception("Could not find patching point");
            }

            cursor.EmitDelegate <Func <bool> >(() => {
                if (!this.InRandomizer)
                {
                    return(false);
                }

                var level = Engine.Scene as Level ?? throw new Exception("what");
                var dyn   = new DynData <LevelData>(level.Session.LevelData);
                if (dyn.Get <string>("CustomWarp") == null)
                {
                    return(false);
                }

                var targetLevel = level.Session.MapData.Get(dyn.Get <string>("CustomWarp"));
                var player      = level.Tracker.GetEntity <Player>();
                level.Add(new Entity {
                    new Coroutine(this.FakeoutWarp(level, player, targetLevel))
                });
                return(true);
            });
            cursor.Emit(OpCodes.Or);
        }
        private static void Player_DashBegin(On.Celeste.Player.orig_DashBegin orig, Player self)
        {
            orig(self);

            if (HasDreamTunnelDash)
            {
                dreamTunnelDashAttacking = true;
                dreamTunnelDashTimer     = self.GetData().Get <float>("dashAttackTimer");

                // Ensures the player enters the dream tunnel dash state if dashing into a fast moving block
                // Because of how it works, it removes dashdir leniency :(
                DynData <Player> playerData = self.GetData();
                Vector2          lastAim    = Input.GetAimVector(self.Facing);
                Vector2          dir        = lastAim.Sign();
                if (!self.CollideCheck <Solid, DreamBlock>() && self.CollideCheck <Solid, DreamBlock>(self.Position + dir))
                {
                    self.Speed = self.DashDir = lastAim;
                    self.MoveHExact((int)dir.X, playerData.Get <Collision>("onCollideH"));
                    self.MoveVExact((int)dir.Y, playerData.Get <Collision>("onCollideV"));
                }

                if (NextDashFeather)
                {
                    FeatherMode     = true;
                    NextDashFeather = false;
                }
            }
            HasDreamTunnelDash = false;
        }
예제 #7
0
        private static void modDeathSound(ILContext il)
        {
            ILCursor       cursor    = new ILCursor(il);
            FieldReference refToThis = HookHelper.FindReferenceToThisInCoroutine(cursor);

            if (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdstr("event:/new_content/char/madeline/death_golden")))
            {
                Logger.Log("CollabUtils2/StrawberryHooks", $"Modding golden death sound at {cursor.Index} in IL for PlayerDeadBody.DeathRoutine");

                // we want to replace the vanilla death sound with the silver berry one if carrying a silver berry.
                cursor.Emit(OpCodes.Ldarg_0);
                cursor.Emit(OpCodes.Ldfld, refToThis);
                cursor.EmitDelegate <Func <string, PlayerDeadBody, string> >((orig, self) => {
                    DynData <PlayerDeadBody> data = new DynData <PlayerDeadBody>(self);
                    bool hasSilver     = data.Get <bool>("hasSilver");
                    bool hasSpeedBerry = data.Get <bool>("hasSpeedBerry");
                    if (hasSilver && hasSpeedBerry)
                    {
                        return("event:/SC2020_silverTimedBerry_death");
                    }
                    if (hasSilver)
                    {
                        return("event:/SC2020_silverBerry_death");
                    }
                    if (hasSpeedBerry)
                    {
                        return("event:/SC2020_timedBerry_death");
                    }
                    return(orig);
                });
            }
        }
        private static bool onSwitchActivate(On.Celeste.Switch.orig_Activate orig, Switch self)
        {
            if (self.Entity.GetType().ToString() == "Celeste.Mod.OutbackHelper.MovingTouchSwitch")
            {
                DynData <TouchSwitch> selfData = new DynData <TouchSwitch>((TouchSwitch)self.Entity);
                if (selfData.Data.ContainsKey("flag"))
                {
                    DynData <Switch> selfSwitch = new DynData <Switch>(self);
                    string           flag       = selfData.Get <string>("flag");
                    Level            level      = self.Entity.SceneAs <Level>();

                    // do what the regular Switch.Activate() method does
                    if (self.Finished || self.Activated)
                    {
                        return(false);
                    }
                    selfSwitch["Activated"] = true;
                    if (self.OnActivate != null)
                    {
                        self.OnActivate();
                    }

                    // use the same logic as flag touch switches to determine if the group is complete.
                    return(FlagTouchSwitch.HandleCollectedFlagTouchSwitch(flag, inverted: false, selfData.Get <bool>("persistent"), level, selfData.Get <int>("id"),
                                                                          selfData.Get <List <FlagTouchSwitch> >("allTouchSwitchesInRoom"), selfData.Get <List <TouchSwitch> >("allMovingFlagTouchSwitchesInRoom"), () => { }));
                }
            }

            // if we are here, it means we aren't dealing with a flag moving touch switch.
            // so, we want regular behavior!
            return(orig(self));
        }
예제 #9
0
        public IEnumerator RefillRoutine(Player player)
        {
            Celeste.Freeze(0.025f);

            baseData.Get <Sprite>("sprite").Visible = baseData.Get <Sprite>("flash").Visible = false;
            bool oneUse = baseData.Get <bool>("oneUse");

            if (!oneUse)
            {
                baseData.Get <Image>("outline").Visible = true;
            }
            yield return(0.05);

            player.StateMachine.State = 0;
            float angle = player.Speed.Angle();
            Level level = baseData.Get <Level>("level");

            level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, angle - (float)Math.PI / 2f);
            level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, angle + (float)Math.PI / 2f);
            SlashFx.Burst(Position, angle);
            if (oneUse)
            {
                RemoveSelf();
            }
        }
예제 #10
0
        public FancyFinalBossMovingBlock(EntityData data, Vector2 offset)
            : base(data.NodesWithPosition(offset), data.Width, data.Height, data.Int("nodeIndex", 0))
        {
            baseData = new DynData <FinalBossMovingBlock>(this);
            Remove(baseData.Get <TileGrid>("sprite"));
            Remove(baseData.Get <TileGrid>("highlight"));
            Remove(Get <TileInterceptor>());
            badLightOcclude = Get <LightOcclude>();

            tileMap            = GenerateTileMap(data.Attr("tileData", ""));
            tileMapHighlighted = GenerateTileMap(data.Attr("tileDataHighlight", ""));

            int newSeed = Calc.Random.Next();

            Calc.PushRandom(newSeed);
            baseData["sprite"] = GFX.FGAutotiler.GenerateMap(tileMap, default(Autotiler.Behaviour)).TileGrid;
            Add(baseData.Get <TileGrid>("sprite"));
            Calc.PopRandom();
            Calc.PushRandom(newSeed);
            TileGrid highlight = GFX.FGAutotiler.GenerateMap(tileMapHighlighted, default(Autotiler.Behaviour)).TileGrid;

            highlight.Alpha       = 0f;
            baseData["highlight"] = highlight;
            Add(baseData.Get <TileGrid>("highlight"));
            Calc.PopRandom();

            Add(new TileInterceptor(baseData.Get <TileGrid>("sprite"), false));


            highlightCollider = GenerateBetterColliderGrid(tileMapHighlighted, 8, 8);
            collider          = GenerateBetterColliderGrid(tileMap, 8, 8);
            AddLightOcclude(this, collider);
            Collider = collider;
        }
        public override void Added(Scene scene)
        {
            // if the gate was already opened on that save or in that session, open the door right away by setting the flag.
            (scene as Level).Session.SetFlag("opened_heartgem_door_" + Requires,
                                             (scene as Level).Session.GetFlag("opened_mini_heart_door_" + entityID) || CollabModule.Instance.SaveData.OpenedMiniHeartDoors.Contains(GetDoorSaveDataID(scene)));

            base.Added(scene);

            DynData <HeartGemDoor> self = new DynData <HeartGemDoor>(this);

            TopSolid    = self.Get <Solid>("TopSolid");
            BottomSolid = self.Get <Solid>("BotSolid");

            // resize the gate: it shouldn't take the whole screen height.
            TopSolid.Collider.Height    = height;
            BottomSolid.Collider.Height = height;
            TopSolid.Top       = Y - height;
            BottomSolid.Bottom = Y + height;

            if (Opened)
            {
                // place the blocks correctly in an open position.
                float openDistance = self.Get <float>("openDistance");
                TopSolid.Collider.Height    -= openDistance;
                BottomSolid.Collider.Height -= openDistance;
                BottomSolid.Top             += openDistance;
            }
        }
예제 #12
0
        public override void Render()
        {
            SamplerState before       = null;
            Matrix       beforeMatrix = default;

            if (cleanSampling || respectScreenShake)
            {
                Draw.SpriteBatch.End();
                before       = spriteBatchData.Get <SamplerState>("samplerState");
                beforeMatrix = spriteBatchData.Get <Matrix>("transformMatrix");
                Draw.SpriteBatch.Begin(SpriteSortMode.Deferred,
                                       spriteBatchData.Get <BlendState>("blendState"),
                                       cleanSampling ? SamplerState.PointClamp : before,
                                       spriteBatchData.Get <DepthStencilState>("depthStencilState"),
                                       spriteBatchData.Get <RasterizerState>("rasterizerState"),
                                       spriteBatchData.Get <Effect>("customEffect"),
                                       beforeMatrix * (respectScreenShake ? Matrix.CreateTranslation(new Vector3(-level.ShakeVector.X, -level.ShakeVector.Y, 0) * 6) : Matrix.Identity));
            }
            base.Render();
            if (cleanSampling)
            {
                Draw.SpriteBatch.End();
                Draw.SpriteBatch.Begin(SpriteSortMode.Deferred,
                                       spriteBatchData.Get <BlendState>("blendState"),
                                       before,
                                       spriteBatchData.Get <DepthStencilState>("depthStencilState"),
                                       spriteBatchData.Get <RasterizerState>("rasterizerState"),
                                       spriteBatchData.Get <Effect>("customEffect"),
                                       beforeMatrix);
            }
        }
        private static void ModHitbox(On.Monocle.Entity.orig_DebugRender orig, Entity self, Camera camera)
        {
            if (!CelesteTasModule.Settings.ShowHitboxes)
            {
                orig(self, camera);
                return;
            }

            orig(self, camera);

            if (self is FinalBossBeam finalBossBeam)
            {
                DynData <FinalBossBeam> dynData = finalBossBeam.GetDynDataInstance();
                if (dynData.Get <float>("chargeTimer") <= 0f && dynData.Get <float>("activeTimer") > 0f)
                {
                    FinalBoss boss    = dynData.Get <FinalBoss>("boss");
                    float     angle   = dynData.Get <float>("angle");
                    Vector2   vector  = boss.BeamOrigin + Calc.AngleToVector(angle, 12f);
                    Vector2   vector2 = boss.BeamOrigin + Calc.AngleToVector(angle, 2000f);
                    Vector2   value   = (vector2 - vector).Perpendicular().SafeNormalize(2f);
                    Player    player  = boss.Scene.CollideFirst <Player>(vector + value, vector2 + value);
                    Draw.Line(vector + value, vector2 + value, Color.Aqua);
                    Draw.Line(vector - value, vector2 - value, Color.Aqua);
                    Draw.Line(vector, vector2, Color.Aqua);
                }
            }
        }
예제 #14
0
        public FancyFallingBlock(EntityData data, Vector2 offset)
            : base(data.Position + offset, '3', data.Width, data.Height, data.Bool("finalBoss", false), data.Bool("behind", false), data.Bool("climbFall", true))
        {
            baseData = new DynData <FallingBlock>(this);
            Remove(baseData.Get <TileGrid>("tiles"));
            Remove(Get <TileInterceptor>());
            badLightOcclude = Get <LightOcclude>();

            int newSeed = Calc.Random.Next();

            Calc.PushRandom(newSeed);
            tileMap = GenerateTileMap(data.Attr("tileData", ""));
            Autotiler.Generated generated = GFX.FGAutotiler.GenerateMap(tileMap, default(Autotiler.Behaviour));
            baseData["tiles"] = generated.TileGrid;
            Add(baseData.Get <TileGrid>("tiles"));
            Add(animatedTiles = generated.SpriteOverlay);
            Calc.PopRandom();

            if (data.Bool("finalBoss", false))
            {
                VirtualMap <char> tileMapHighlighted = GenerateTileMap(data.Attr("tileDataHighlight", ""));
                Calc.PushRandom(newSeed);
                TileGrid highlight = GFX.FGAutotiler.GenerateMap(tileMapHighlighted, default(Autotiler.Behaviour)).TileGrid;
                highlight.Alpha       = 0f;
                baseData["highlight"] = highlight;
                Add(baseData.Get <TileGrid>("highlight"));
                Calc.PopRandom();
            }

            ColliderList colliders = GenerateBetterColliderGrid(tileMap, 8, 8);

            AddLightOcclude(this, colliders);
            Collider = colliders;
            Add(new TileInterceptor(baseData.Get <TileGrid>("tiles"), false));
        }
예제 #15
0
        private static bool PlayerUseRefill(On.Celeste.Player.orig_UseRefill orig, Player self, bool twoDashes)
        {
            DynData <Player> selfData = new DynData <Player>(self);

            if (selfData.Data.ContainsKey("DJMapHelper_RefillColor") && selfData["DJMapHelper_RefillColor"] != null)
            {
                bool result;

                switch (selfData.Get <RefillColor>("DJMapHelper_RefillColor"))
                {
                case RefillColor.Red:
                    result = PlayerUseRedRefill(self);
                    break;

                case RefillColor.Blue:
                    result = PlayerUseBlueRefill(self);
                    break;

                case RefillColor.Black:
                    result = PlayerUseBlackRefill(self);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(color), selfData.Get <RefillColor>("DJMapHelper_RefillColor"), null);
                }

                selfData["DJMapHelper_RefillColor"] = null;
                return(result);
            }
            else
            {
                return(orig(self, twoDashes));
            }
        }
예제 #16
0
        private void GameSelectionPanel_Display(On.GameSelectionPanel.orig_Display orig, GameSelectionPanel self, bool isMultiplayer, string mpSaveKey, int slotCount, GameSelectionPanel.GameSelectionFinishedHandler onGameSelectionFinished)
        {
            Log("Attempting to Display!");
            IDatabase <ShipConfig> db = Databases.GetDatabase <ShipConfig>(false);

            Log("Database loaded!");
            if (db.GetValue(this.GetConfig().Name) != null)
            {
                // It already exists within the database, so we can continue
                Log("The shipconfig with name: " + this.GetConfig().Name + " already exists inside the database!");
            }
            else
            {
                db.Add(this.GetConfig());
            }
            DynData <GameSelectionPanel> paneldyn = new DynData <GameSelectionPanel>(self);

            paneldyn.Set <IDatabase <ShipConfig> >("shipConfigDB", db);
            Log("Database set!");

            orig(self, isMultiplayer, mpSaveKey, slotCount, onGameSelectionFinished);

            Log("Available Ships:");
            foreach (string s in paneldyn.Get <List <Amplitude.StaticString> >("availableShips"))
            {
                Log(s);
            }
            Log("DB:");
            foreach (ShipConfig s in paneldyn.Get <IDatabase <ShipConfig> >("shipConfigDB"))
            {
                Log("Name: " + s.Name + " localized: " + s.GetLocalizedName() + " desc: " + s.GetLocalizedDescription() + " abscissa val: " + s.AbscissaValue);
            }
        }
        public DreamBlockDebris Init(Vector2 pos, DreamBlockDummy block = null)
        {
            orig_Init(pos, '1');

            Block = block ?? new DreamBlockDummy(this);
            Image image = baseData.Get <Image>("image");

            Remove(image);
            Sprite sprite = new Sprite(GFX.Game, "objects/CommunalHelper/dreamMoveBlock/");
            float  speed  = Calc.Random.NextFloat(0.3f) + 0.1f;

            sprite.AddLoop("active", "debris", speed);
            sprite.AddLoop("disabled", "disabledDebris", speed);
            sprite.CenterOrigin();
            sprite.Color    = image.Color;
            sprite.Rotation = image.Rotation;
            sprite.Scale    = image.Scale;
            sprite.FlipX    = image.FlipX;
            sprite.FlipY    = image.FlipY;

            Add(sprite);
            sprite.Play(Block.PlayerHasDreamDash ? "active" : "disabled", randomizeFrame: true);
            baseData["image"] = this.sprite = sprite;

            if (Calc.Random.Next(4) == 0)
            {
                activePointColor   = Calc.Random.Choose(activeParticleColors);
                disabledPointColor = Color.LightGray * (0.5f + Calc.Random.Choose(0, 1, 1, 2, 2, 2) / 2f * 0.5f);
                pointOffset        = new Vector2(Calc.Random.Next(-2, 2), Calc.Random.Next(-2, 2));
            }

            return(this);
        }
예제 #18
0
        public override void Update()
        {
            base.Update();

            // if we are supposed to push the player and the player is hitting us...
            Player p;

            if (pushPlayer && (p = CollideFirst <Player>()) != null)
            {
                DynData <Player> playerData = new DynData <Player>(p);
                if (AllowLeftToRight)
                {
                    // player is moving right, not on the ground, not climbing, not blocked => push them to the right
                    if (p.Speed.X >= 0f && !playerData.Get <bool>("onGround") && (p.StateMachine.State != 1 || playerData.Get <int>("lastClimbMove") == -1) &&
                        !((bool)playerJumpthruBoostBlockedCheck.Invoke(p, new object[0])))
                    {
                        p.MoveH(40f * Engine.DeltaTime);
                    }
                }
                else
                {
                    // player is moving left, not on the ground, not climbing, not blocked => push them to the left
                    if (p.Speed.X <= 0f && !playerData.Get <bool>("onGround") && (p.StateMachine.State != 1 || playerData.Get <int>("lastClimbMove") == -1) &&
                        !((bool)playerJumpthruBoostBlockedCheck.Invoke(p, new object[0])))
                    {
                        p.MoveH(-40f * Engine.DeltaTime);
                    }
                }
            }
        }
예제 #19
0
        protected DashStateRefill(EntityData data, Vector2 offset)
            : base(data, offset)
        {
            baseData = new DynData <Refill>(this);

            respawnTime = data.Float("respawnTime", 2.5f); // default is 2.5 sec.

            Get <PlayerCollider>().OnCollide = OnPlayer;

            if (TryCreateCustomSprite(out Sprite sprite))
            {
                Remove(baseData.Get <Sprite>("sprite"));
                Add(sprite);
                baseData["sprite"] = sprite;
            }

            if (TryCreateCustomOutline(out Sprite outline))
            {
                Remove(baseData.Get <Sprite>("outline"));
                Add(outline);
                baseData["outline"] = outline;
            }

            if (TryCreateCustomFlash(out Sprite flash))
            {
                Remove(baseData.Get <Sprite>("flash"));
                Add(flash);
                baseData["flash"] = flash;
            }
        }
 internal static void Break(On.Celeste.CrumbleWallOnRumble.orig_Break orig, CrumbleWallOnRumble self)
 {
     if (self is FancyCrumbleWallOnRumble)
     {
         if (self.Collidable && self.Scene != null)
         {
             FancyCrumbleWallOnRumble block = (self as FancyCrumbleWallOnRumble);
             Audio.Play("event:/new_content/game/10_farewell/quake_rockbreak", block.Position);
             block.Collidable = false;
             for (int x = 0; x < block.Width / 8f; x++)
             {
                 for (int y = 0; y < block.Height / 8f; y++)
                 {
                     if (!IsEmpty(block.tileMap[x, y]) && !block.Scene.CollideCheck <Solid>(new Rectangle((int)block.X + x * 8, (int)block.Y + y * 8, 8, 8)))
                     {
                         block.Scene.Add(Engine.Pooler.Create <Debris>().Init(block.Position + new Vector2(4 + x * 8, 4 + y * 8), block.tileMap[x, y], true).BlastFrom(block.TopCenter));
                     }
                 }
             }
             DynData <CrumbleWallOnRumble> blockData = new DynData <CrumbleWallOnRumble>(block);
             if (blockData.Get <bool>("permanent"))
             {
                 block.SceneAs <Level>().Session.DoNotLoad.Add(blockData.Get <EntityID>("id"));
             }
             block.RemoveSelf();
         }
     }
     else
     {
         orig(self);
     }
 }
예제 #21
0
        protected void ReplaceSprite(Sprite newSprite)
        {
            Sprite oldSprite = BoosterData.Get <Sprite>("sprite");

            Remove(oldSprite);
            BoosterData["sprite"] = newSprite;
            Add(newSprite);
        }
예제 #22
0
 public static void CollectedPieces(DynData <HeartGem> heartData)
 {
     heartData.Target.Visible    = true;
     heartData.Target.Active     = true;
     heartData.Target.Collidable = true;
     heartData.Get <BloomPoint>("bloom").Visible = heartData.Get <VertexLight>("light").Visible = true;
     heartData.Target.SceneAs <Level>().Session.SetFlag(GotShardFlag(heartData));
 }
        public ReskinnableCrushBlock(EntityData data, Vector2 offset) : base(data, offset)
        {
            DynData <CrushBlock> self = new DynData <CrushBlock>(this);
            bool   giant = self.Get <bool>("giant");
            Sprite face  = self.Get <Sprite>("face");

            // rebuild the face in code with the sprites in our custom directory.
            face.Reset(GFX.Game, spriteDirectory + "/");
            if (giant)
            {
                /*
                 * <Loop id="idle" path="giant_block" frames="0" delay="0.08"/>
                 * <Anim id="hurt"  path="giant_block" frames="8-12" delay="0.08" goto="idle"/>
                 * <Anim id="hit" path="giant_block" frames="0-5" delay="0.08"/>
                 * <Loop id="right" path="giant_block" frames="6,7"  delay="0.08"/>
                 */
                face.AddLoop("idle", "giant_block", 0.08f, 0);
                face.Add("hurt", "giant_block", 0.08f, "idle", 8, 9, 10, 11, 12);
                face.Add("hit", "giant_block", 0.08f, 0, 1, 2, 3, 4, 5);
                face.AddLoop("right", "giant_block", 0.08f, 6, 7);
            }
            else
            {
                /*
                 * <Loop id="idle" path="idle_face" delay="0.08"/>
                 * <Anim id="hurt" path="hurt" frames="3-12" delay="0.08" goto="idle"/>
                 * <Anim id="hit" path="hit" delay="0.08"/>
                 * <Loop id="left" path="hit_left" delay="0.08"/>
                 * <Loop id="right" path="hit_right" delay="0.08"/>
                 * <Loop id="up" path="hit_up" delay="0.08"/>
                 * <Loop id="down" path="hit_down" delay="0.08"/>
                 */

                face.AddLoop("idle", "idle_face", 0.08f);
                face.Add("hurt", "hurt", 0.08f, "idle", 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
                face.Add("hit", "hit", 0.08f);
                face.AddLoop("left", "hit_left", 0.08f);
                face.AddLoop("right", "hit_right", 0.08f);
                face.AddLoop("up", "hit_up", 0.08f);
                face.AddLoop("down", "hit_down", 0.08f);
            }
            face.CenterOrigin();
            face.Play("idle");

            // customize the fill color.
            self["fill"] = Calc.HexToColor(data.Attr("fillColor", "62222b"));

            crushParticleColor = new ParticleType(P_Crushing)
            {
                Color  = Calc.HexToColor(data.Attr("crushParticleColor1", "ff66e2")),
                Color2 = Calc.HexToColor(data.Attr("crushParticleColor2", "68fcff"))
            };
            activateParticleColor = new ParticleType(P_Activate)
            {
                Color  = Calc.HexToColor(data.Attr("activateParticleColor1", "5fcde4")),
                Color2 = Calc.HexToColor(data.Attr("activateParticleColor2", "ffffff"))
            };
        }
        public static Entity Load(Level level, LevelData levelData, Vector2 offset, EntityData entityData)
        {
            string flag = entityData.Attr("flag");

            if (level.Session.GetFlag(flag) || level.Session.GetFlag(flag + "_switch" + entityData.ID))
            {
                // moving touch switches can't be persistent, but we can very much spawn a flag touch switch instead!
                Vector2[] nodes        = entityData.Nodes;
                Vector2   origPosition = entityData.Position;
                entityData.Position = nodes[nodes.Length - 1];
                FlagTouchSwitch flagTouchSwitch = new FlagTouchSwitch(entityData, offset);
                entityData.Position = origPosition;
                return(flagTouchSwitch);
            }
            else
            {
                // build the moving touch switch
                TouchSwitch movingTouchSwitch = (TouchSwitch)Activator.CreateInstance(movingTouchSwitchType,
                                                                                      new object[] { entityData.NodesOffset(offset), entityData, offset });

                // save its attributes as DynData
                DynData <TouchSwitch> switchData = new DynData <TouchSwitch>(movingTouchSwitch);
                switchData["flag"]        = entityData.Attr("flag");
                switchData["id"]          = entityData.ID;
                switchData["persistent"]  = entityData.Bool("persistent", false);
                switchData["movingColor"] = Calc.HexToColor(entityData.Attr("movingColor", "FF8080"));

                // these attributes actually exist in TouchSwitch and as such, they work!
                switchData["inactiveColor"]   = Calc.HexToColor(entityData.Attr("inactiveColor", "5FCDE4"));
                switchData["activeColor"]     = Calc.HexToColor(entityData.Attr("activeColor", "FFFFFF"));
                switchData["finishColor"]     = Calc.HexToColor(entityData.Attr("finishColor", "F141DF"));
                switchData["P_RecoloredFire"] = new ParticleType(TouchSwitch.P_Fire)
                {
                    Color = switchData.Get <Color>("finishColor")
                };

                // set up the icon
                string iconAttribute = entityData.Attr("icon", "vanilla");
                Sprite icon          = new Sprite(GFX.Game, iconAttribute == "vanilla" ? "objects/touchswitch/icon" : $"objects/MaxHelpingHand/flagTouchSwitch/{iconAttribute}/icon");
                icon.Add("idle", "", 0f, default(int));
                icon.Add("spin", "", 0.1f, new Chooser <string>("spin", 1f), 0, 1, 2, 3, 4, 5);
                icon.Play("spin");
                icon.Color = switchData.Get <Color>("inactiveColor");
                icon.CenterOrigin();
                movingTouchSwitch.Remove(movingTouchSwitch.Get <Sprite>());
                movingTouchSwitch.Add(icon);
                movingTouchSwitchIcon.SetValue(movingTouchSwitch, icon);
                switchData["icon"] = icon;

                // collect the list of flag touch switches in the room as soon as the entity is awake, like regular flag touch switches.
                movingTouchSwitch.Add(new TouchSwitchListAttacher(entityData.Attr("flag")));

                return(movingTouchSwitch);
            }
        }
예제 #25
0
        public override void Added(Scene scene)
        {
            base.Added(scene);

            // fix the bloom to match golden alpha
            DynData <Strawberry> self = new DynData <Strawberry>(this);

            self.Get <BloomPoint>("bloom").Alpha = 0.5f;

            if (CollabMapDataProcessor.SilverBerries.ContainsKey(levelSet))
            {
                int missingBerries = 0;
                int totalBerries   = CollabMapDataProcessor.SilverBerries[levelSet].Count;
                foreach (KeyValuePair <string, EntityID> requiredSilver in CollabMapDataProcessor.SilverBerries[levelSet])
                {
                    // check if the silver was collected.
                    AreaStats stats = SaveData.Instance.GetAreaStatsFor(AreaData.Get(requiredSilver.Key).ToKey());
                    if (!stats.Modes[0].Strawberries.Contains(requiredSilver.Value))
                    {
                        // this berry wasn't collected!
                        missingBerries++;
                    }
                }

                if (missingBerries != 0)
                {
                    // some berries are missing, spawn the hologram instead of the berry.
                    HoloRainbowBerry hologram = new HoloRainbowBerry(Position, totalBerries - missingBerries, totalBerries);
                    scene.Add(hologram);

                    RemoveSelf();
                }
                else
                {
                    // all berries are here! check if we should play the unlock cutscene.
                    if (!CollabModule.Instance.SaveData.CombinedRainbowBerries.Contains((scene as Level).Session.Area.GetSID()))
                    {
                        // spawn the hologram for the animation...
                        HoloRainbowBerry hologram = new HoloRainbowBerry(Position, totalBerries, totalBerries);
                        hologram.Tag = Tags.FrozenUpdate;
                        scene.Add(hologram);

                        // make rainbow berry invisible for now...
                        Visible    = false;
                        Collidable = false;
                        self.Get <BloomPoint>("bloom").Visible = (self.Get <VertexLight>("light").Visible = false);

                        // now we wait for the player to enter the trigger. filling the HologramForCutscene field will tell the trigger to create the cutscene.
                        HologramForCutscene  = hologram;
                        CutsceneTotalBerries = totalBerries;
                    }
                }
            }
        }
예제 #26
0
        public FancyIntroCrusher(EntityData data, Vector2 offset)
            : base(data, offset)
        {
            baseData = new DynData <IntroCrusher>(this);
            Remove(baseData.Get <TileGrid>("tilegrid"));

            tileMap  = GenerateTileMap(data.Attr("tileData", ""));
            Collider = GenerateBetterColliderGrid(tileMap, 8, 8);

            baseData["tilegrid"] = GFX.FGAutotiler.GenerateMap(tileMap, default(Autotiler.Behaviour)).TileGrid;
            Add(baseData.Get <TileGrid>("tilegrid"));
        }
예제 #27
0
        public override void Added(Scene scene)
        {
            base.Added(scene);

            if (notCoreMode)
            {
                // revert the activation of fire mode bumper.
                DynData <Bumper> thisBumper = new DynData <Bumper>(this);
                thisBumper["fireMode"] = false;
                thisBumper.Get <Sprite>("spriteEvil").Visible = false;
                thisBumper.Get <Sprite>("sprite").Visible     = true;
            }
        }
예제 #28
0
        private static void hookSeekerBarrierParticles(On.Celeste.SeekerBarrier.orig_Update orig, SeekerBarrier self)
        {
            float particleDirection = controllerOnScreen?.particleDirection ?? 0f;

            if (self is CustomSeekerBarrier customBarrier)
            {
                particleDirection = customBarrier.particleDirection;
            }

            // no need to account for screen transitions: particles are frozen during them.
            if (particleDirection == 0f)
            {
                // default settings: do nothing
                orig(self);
                return;
            }

            // save all particles
            DynData <SeekerBarrier> selfData  = new DynData <SeekerBarrier>(self);
            List <Vector2>          particles = new List <Vector2>(selfData.Get <List <Vector2> >("particles"));

            float[] speeds = selfData.Get <float[]>("speeds");

            // run vanilla code
            orig(self);

            // move particles again ourselves, except on the direction we want.
            for (int i = 0; i < particles.Count; i++)
            {
                // compute new position
                Vector2 newPosition = particles[i] + Vector2.UnitY.Rotate((float)(particleDirection * Math.PI / 180)) * speeds[i % speeds.Length] * Engine.DeltaTime;

                // make sure it stays in bounds
                while (newPosition.X < 0)
                {
                    newPosition.X += self.Width;
                }
                while (newPosition.Y < 0)
                {
                    newPosition.Y += self.Height;
                }
                newPosition.X %= self.Width;
                newPosition.Y %= self.Height;

                // replace the particle position
                particles[i] = newPosition;
            }

            // replace them.
            selfData["particles"] = particles;
        }
예제 #29
0
        public MoreCustomNPC(EntityData data, Vector2 offset, EntityID id) : base(data, offset, id)
        {
            hasDialogue = !string.IsNullOrEmpty(data.Attr("dialogId"));

            DynData <CustomNPC> npcData = new DynData <CustomNPC>(this);

            string spriteName = data.Attr("spriteName", "");

            if (!string.IsNullOrEmpty(spriteName))
            {
                // replace the NPC texture with a sprite.
                npcData["textures"] = null;

                sprite       = GFX.SpriteBank.Create(spriteName);
                sprite.Scale = npcData.Get <Vector2>("scale");
                Add(sprite);
            }

            string frames = data.Attr("frames", "");

            if (!string.IsNullOrEmpty(frames))
            {
                // "textures" currently contains all frames, but we only want some.
                List <MTexture> npcTextures = npcData.Get <List <MTexture> >("textures");
                List <MTexture> allTextures = new List <MTexture>(npcTextures);

                // clear the texture list, then only add back the textures we want!
                npcTextures         = new List <MTexture>();
                npcData["textures"] = npcTextures;
                foreach (int frame in Calc.ReadCSVIntWithTricks(frames))
                {
                    npcTextures.Add(allTextures[frame]);
                }
            }

            if (data.Nodes.Length >= 2)
            {
                // the nodes define a "talker zone", with one being the top left, and the other the bottom right.
                // we're adding 8 to bottom and right because nodes are rendered as 8x8 rectangles in Ahorn,
                // and we want to take the bottom/right of those rectangles.
                Vector2[] nodesOffset = data.NodesOffset(offset);
                float     top         = Math.Min(nodesOffset[0].Y, nodesOffset[1].Y);
                float     bottom      = Math.Max(nodesOffset[0].Y, nodesOffset[1].Y) + 8;
                float     left        = Math.Min(nodesOffset[0].X, nodesOffset[1].X);
                float     right       = Math.Max(nodesOffset[0].X, nodesOffset[1].X) + 8;

                talkerZone = new Rectangle((int)(left - Position.X), (int)(top - Position.Y), (int)(right - left), (int)(bottom - top));
            }
        }
예제 #30
0
        private Session onSessionRestart(On.Celeste.Session.orig_Restart orig, Session self, string intoLevel)
        {
            Session session = orig(self, intoLevel);

            if (Settings.AllStrawberriesAreGoldens && Engine.Scene is LevelExit levelExit)
            {
                DynData <LevelExit> exitData = new DynData <LevelExit>(levelExit);
                if (exitData.Get <LevelExit.Mode>("mode") == LevelExit.Mode.GoldenBerryRestart && exitData.Data.ContainsKey("playerInventoryToRestore"))
                {
                    session.Inventory = exitData.Get <PlayerInventory>("playerInventoryToRestore");
                }
            }

            return(session);
        }