private EntityData generateBadelineEntityData(Level level, int badelineNumber)
        {
            EntityData entityData = ExtendedVariantsModule.GenerateBasicEntityData(level, badelineNumber);

            entityData.Values["canChangeMusic"] = false;
            return(entityData);
        }
Esempio n. 2
0
 private float determineDelayBetweenSnowballs()
 {
     if (ExtendedVariantsModule.ShouldIgnoreCustomDelaySettings())
     {
         return(0.8f);
     }
     return(Settings.SnowballDelay / 10f);
 }
        private void modLoadLevel(On.Celeste.Level.orig_LoadLevel orig, Level self, Player.IntroTypes playerIntro, bool isFromLoader)
        {
            orig(self, playerIntro, isFromLoader);

            // if we killed the slowdown earlier, stop now!
            killSeekerSlowdownToFixHeart = false;

            Level  level  = self;
            Player player = level.Tracker.GetEntity <Player>();

            if (player != null && Settings.AddSeekers != 0)
            {
                // make the seeker barriers temporarily collidable so that they are taken in account in Solid collide checks
                // and seekers can't spawn in them
                // (... yes, this is also what vanilla does in the seekers' Update method.)
                foreach (Entity entity in self.Tracker.GetEntities <SeekerBarrier>())
                {
                    entity.Collidable = true;
                }

                for (int seekerCount = 0; seekerCount < Settings.AddSeekers; seekerCount++)
                {
                    for (int i = 0; i < 100; i++)
                    {
                        // roll a seeker position in the room
                        int x = randomGenerator.Next(level.Bounds.Width) + level.Bounds.X;
                        int y = randomGenerator.Next(level.Bounds.Height) + level.Bounds.Y;

                        // should be at least 100 pixels from the player
                        double playerDistance = Math.Sqrt(Math.Pow(MathHelper.Distance(x, player.X), 2) + Math.Pow(MathHelper.Distance(y, player.Y), 2));

                        // also check if we are not spawning in a wall, that would be a shame
                        Rectangle collideRectangle = new Rectangle(x - 8, y - 8, 16, 16);
                        if (playerDistance > 100 && !level.CollideCheck <Solid>(collideRectangle) && !level.CollideCheck <Seeker>(collideRectangle))
                        {
                            // build a Seeker with a proper EntityID to make Speedrun Tool happy (this is useless in vanilla Celeste but the constructor call is intercepted by Speedrun Tool)
                            EntityData seekerData = ExtendedVariantsModule.GenerateBasicEntityData(level, 10 + seekerCount);
                            seekerData.Position = new Vector2(x, y);
                            Seeker seeker = new AutoDestroyingSeeker(seekerData, Vector2.Zero);
                            level.Add(seeker);
                            break;
                        }
                    }
                }

                foreach (Entity entity in self.Tracker.GetEntities <SeekerBarrier>())
                {
                    entity.Collidable = false;
                }

                if (playerIntro != Player.IntroTypes.Transition)
                {
                    level.Entities.UpdateLists();
                }
            }
        }
Esempio n. 4
0
        public override void Update()
        {
            base.Update();

            Player player = SceneAs <Level>().Tracker.GetEntity <Player>();

            if (ExtendedVariantsModule.ShouldEntitiesAutoDestroy(player))
            {
                RemoveSelf();
            }
        }
        public override void Update()
        {
            base.Update();

            Player player = SceneAs <Level>().Tracker.GetEntity <Player>();

            if (player != null && ExtendedVariantsModule.ShouldEntitiesAutoDestroy(player) && !triggeredLeave)
            {
                // we should destroy lava/ice
                Leave();
                triggeredLeave = true;
            }
        }
Esempio n. 6
0
        public override void Update()
        {
            base.Update();

            Level  level  = SceneAs <Level>();
            Player player = level.Tracker.GetEntity <Player>();

            if (ExtendedVariantsModule.ShouldEntitiesAutoDestroy(player))
            {
                // during cutscenes, tell Oshiro to get outta here the same way as Badeline
                // (we can't use the "official" way of making him leave because that doesn't cancel his attack.
                // A Badeline vanish animation looks weird but nicer than a flat out disappearance imo)
                level.Displacement.AddBurst(Entity.Center, 0.5f, 24f, 96f, 0.4f, null, null);
                level.Particles.Emit(BadelineOldsite.P_Vanish, 12, Entity.Center, Vector2.One * 6f);
                Entity.RemoveSelf();

                // make sure that the anxiety set by Oshiro went away (why doesn't that work in real life tho)
                Distort.Anxiety  = 0;
                Distort.GameRate = 1;
            }
        }
        public override void Update()
        {
            // if Badeline is waiting for a watchtower, stop updating it so that she doesn't go forward.
            if (!waitingForWatchtower)
            {
                base.Update();

                Level  level  = SceneAs <Level>();
                Player player = level.Tracker.GetEntity <Player>();

                if (ExtendedVariantsModule.ShouldEntitiesAutoDestroy(player))
                {
                    // we are in a cutscene **but not the Badeline Intro one**
                    // so we should just make the chasers disappear to prevent them from killing the player mid-cutscene
                    level.Displacement.AddBurst(Center, 0.5f, 24f, 96f, 0.4f, null, null);
                    level.Particles.Emit(P_Vanish, 12, Center, Vector2.One * 6f);

                    if (!BadelineChasersEverywhere.UsingWatchtower)
                    {
                        // cutscene!
                        RemoveSelf();
                    }
                    else
                    {
                        // waiting for watchtower: just become invisible instead.
                        waitingForWatchtower = true;
                        Visible = false;
                    }
                }
            }
            else if (!BadelineChasersEverywhere.UsingWatchtower)
            {
                // using the watchtower is over, make Badeline appear again!
                waitingForWatchtower = false;
                Visible = true;

                SceneAs <Level>().Displacement.AddBurst(Center, 0.5f, 24f, 96f, 0.4f, null, null);
                SceneAs <Level>().Particles.Emit(P_Vanish, 12, Center, Vector2.One * 6f);
            }
        }
Esempio n. 8
0
        public override void Update()
        {
            base.Update();

            Player player = SceneAs <Level>().Tracker.GetEntity <Player>();

            if (ExtendedVariantsModule.ShouldEntitiesAutoDestroy(player))
            {
                // kill the boss no matter what
                RemoveSelf();

                // and kill all the beams and shots as well, they could still kill the player!
                foreach (FinalBossShot shot in SceneAs <Level>().Tracker.GetEntities <FinalBossShot>())
                {
                    shot.Destroy();
                }
                foreach (FinalBossBeam beam in SceneAs <Level>().Tracker.GetEntities <FinalBossBeam>())
                {
                    beam.Destroy();
                }
            }
        }
Esempio n. 9
0
        private void injectBadelineBosses(Level level)
        {
            Player player = level.Tracker.GetEntity <Player>();

            if (player != null)
            {
                for (int id = level.Tracker.CountEntities <FinalBoss>(); id < Settings.BadelineBossCount; id++)
                {
                    // let's add a boss

                    Vector2 bossPosition;
                    if (id == 0 && !Settings.FirstBadelineSpawnRandom)
                    {
                        // the first Badeline should spawn at the opposite of the room
                        bossPosition = computeBossPositionAtOppositeOfPlayer(level, player);
                    }
                    else
                    {
                        // all the others should spawn at random points
                        bossPosition = computeBossPositionAtRandom(level, player);
                    }

                    // position not found, abort!
                    if (bossPosition == Vector2.Zero)
                    {
                        break;
                    }

                    Vector2 penultimateNode = player.Position;
                    Vector2 lastNode        = bossPosition;

                    Vector2[] nodes = new Vector2[Settings.BadelineBossNodeCount];

                    for (int i = 0; i < Settings.BadelineBossNodeCount - 1; i++)
                    {
                        // randomize all nodes, except the last one.
                        nodes[i] = computeBossPositionAtRandom(level, player);

                        penultimateNode = lastNode;
                        lastNode        = nodes[i];

                        // position not found, don't process other nodes!
                        if (lastNode == Vector2.Zero)
                        {
                            break;
                        }
                    }

                    // position not found, stop adding bosses!
                    if (lastNode == Vector2.Zero)
                    {
                        break;
                    }

                    if (bossPosition != Vector2.Zero)
                    {
                        Vector2 bossPositionOffscreen = penultimateNode;

                        Vector2 lastMoveDirection = (lastNode - penultimateNode);

                        // extremely unlikely, but better safe than sorry
                        if (lastMoveDirection == Vector2.Zero)
                        {
                            lastMoveDirection = Vector2.One;
                        }

                        while (bossPositionOffscreen.X + 30 > level.Bounds.Left - 50 && bossPositionOffscreen.X < level.Bounds.Right + 50 &&
                               bossPositionOffscreen.Y + 30 > level.Bounds.Top - 50 && bossPositionOffscreen.Y < level.Bounds.Bottom + 50)
                        {
                            // push the position until it is offscreen, using the same direction as the last move (or the player => boss direction if there is no node).
                            bossPositionOffscreen += lastMoveDirection;
                        }

                        // the offscreen position has to be the last node.
                        nodes[nodes.Length - 1] = bossPositionOffscreen;

                        // build the boss
                        EntityData bossData = ExtendedVariantsModule.GenerateBasicEntityData(level, 15 + id); // 0 to 9 are Badeline chasers, 10 to 14 are seekers.
                        bossData.Position = bossPosition;
                        bossData.Values["canChangeMusic"] = false;
                        bossData.Values["cameraLockY"]    = false;
                        bossData.Values["patternIndex"]   = Settings.BadelineAttackPattern == 0 ? patternRandomizer.Next(1, 16) : Settings.BadelineAttackPattern;
                        bossData.Nodes = nodes;

                        // add it to the level!
                        level.Add(new AutoDestroyingBadelineBoss(bossData, Vector2.Zero));
                    }
                }

                level.Entities.UpdateLists();
            }
        }
 private float determineBadelineLag()
 {
     return(ExtendedVariantsModule.ShouldIgnoreCustomDelaySettings() || Settings.BadelineLag == 0 ? 1.55f : Settings.BadelineLag / 10f);
 }