Exemple #1
0
        public override void Use(Entity entity, Item item)
        {
            if (SetToMin)
            {
                entity.GetComponent <HealthComponent>().InitMaxHealth = 1;

                return;
            }

            if (SetToMax)
            {
                var h = entity.GetComponent <HealthComponent>();
                h.ModifyHealth(h.MaxHealth, item);
                return;
            }

            var a = Amount;

            if (a > 0 && Scourge.IsEnabled(Scourge.OfIllness))
            {
                if (a == 1)
                {
                    return;
                }

                a = (int)(a / 2f);
            }

            entity.GetComponent <HealthComponent>().ModifyHealth(a, entity);
        }
Exemple #2
0
        public void InitStats(bool fromInit = false)
        {
            HasFlight = false;
            SuperHot  = false;

            Scourge.Clear();

            GetComponent <AimComponent>().ShowLaserLine = false;
            GetComponent <OrbitGiverComponent>().DestroyAll();
            GetComponent <FollowerComponent>().DestroyAll();

            var hp = GetComponent <HealthComponent>();

            if (fromInit)
            {
                hp.InitMaxHealth = 6;
            }

            hp.MaxHealthCap          = 32;
            hp.InvincibilityTimerMax = 1f;

            if (CheatWindow.AutoGodMode)
            {
                Log.Info("Entering god mode for the player");
                hp.Unhittable = true;
            }
        }
        public override void Use(Entity entity, Item item)
        {
            base.Use(entity, item);
            Scourge.Enable(scourge);

            if (Run.Scourge == 0)
            {
                Run.AddScourge();
            }
        }
        protected override bool TryOpen(Entity entity)
        {
            var item = Scourge.GenerateItemId();

            if (item != null)
            {
                Timer.Add(() => entity.GetComponent <InventoryComponent>().Pickup(Items.CreateAndAdd(item, entity.Area)), 0.3f);
            }

            return(true);
        }
Exemple #5
0
        public override void Paint(Level level)
        {
            Painter.Fill(level, this, 1, Tile.EvilFloor);

            var stand = new ScourgedStand();

            level.Area.Add(stand);
            stand.Center = GetCenter() * 16 + new Vector2(8);

            stand.SetItem(Items.CreateAndAdd(Scourge.GenerateItemId(), level.Area), stand);
        }
        protected override bool Interact(Entity e)
        {
            var c = e.GetComponent <HealthComponent>();

            c.ModifyHealth(c.MaxHealth, this);

            e.GetComponent <InventoryComponent>().Pickup(Items.CreateAndAdd(Scourge.Generate(), Area));
            Break();
            Audio.PlaySfx("level_scourge_statue");

            return(true);
        }
        public override void Happen(Player entity)
        {
            if (amount < 0)
            {
                var sc = Run.Scourge;

                for (var i = 0; i < sc; i++)
                {
                    Run.RemoveScourge();
                }

                var inventory = entity.GetComponent <InventoryComponent>();
                var toRemove  = new List <Item>();

                foreach (var i in inventory.Items)
                {
                    if (i.Scourged)
                    {
                        i.Scourged = false;
                    }

                    if (i.Type == ItemType.Scourge)
                    {
                        toRemove.Add(i);
                    }
                }

                Cleanse(entity.GetComponent <WeaponComponent>());
                Cleanse(entity.GetComponent <ActiveWeaponComponent>());
                Cleanse(entity.GetComponent <ActiveItemComponent>());

                // fixme: doesnt do anything to ui inventory
                foreach (var i in toRemove)
                {
                    inventory.Remove(i, true);
                }

                foreach (var s in Scourge.Defined)
                {
                    Scourge.Disable(s);
                }
            }
            else
            {
                for (var i = 0; i < amount; i++)
                {
                    Run.AddScourge();
                }
            }
        }
        public static void Place(Vector2 where, Area area)
        {
            where.Y -= 16;

            var goblin = new TrashGoblin();

            area.Add(goblin);
            goblin.BottomCenter = where;
            goblin.X           += 1;

            var stand = new TrashGoblinStand();

            area.Add(stand);
            stand.Center = where + new Vector2(0, 4 + stand.Height);

            stand.SetItem(Items.CreateAndAdd(Scourge.GenerateItemId(), area, false), null);
        }
Exemple #9
0
        protected override bool TryPay(Entity entity)
        {
            if (base.TryPay(entity))
            {
                var scourge = Scourge.GenerateItemId();

                if (scourge != null)
                {
                    Timer.Add(() => {
                        entity.GetComponent <InventoryComponent>().Pickup(Items.CreateAndAdd(scourge, entity.Area));
                    }, 2f);
                }

                return(true);
            }

            return(false);
        }
Exemple #10
0
        private void RenderConsumables(bool hasMana)
        {
            var bottomY = 8 + 9 + 8 + (hasMana ? 10 : 0) + (Player.GetComponent <HealthComponent>().MaxHealth + Player.GetComponent <HeartsComponent>().Total > HeartsComponent.PerRow ? 10 : 0) + (int)(12 * (activeSlot.ActivePosition + 1));

            if (Scourge.IsEnabled(Scourge.OfKeys))
            {
                Graphics.Render(question, new Vector2(8, bottomY + 1));
                return;
            }

            Graphics.Render(coin, new Vector2(Wrap(8 + coin.Center.X), bottomY + 1 + coin.Center.Y), 0, coin.Center, coinScale);
            PrintString($"{coins}", 18, bottomY - 1);
            bottomY += 12;

            Graphics.Render(key, new Vector2(Wrap(7 + key.Center.X), bottomY + key.Center.Y + 2), 0, key.Center, keyScale);
            PrintString($"{keys}", 18, bottomY - 1);
            bottomY += bomb.Source.Height + 2;

            Graphics.Render(bomb, new Vector2(Wrap(8 + bomb.Center.X), bottomY + bomb.Center.Y), 0,
                            bomb.Center, bombScale);
            PrintString($"{bombs}", 18, bottomY - 1);
        }
Exemple #11
0
        static HappeningRegistry()
        {
            // Bad
            Add("omega_hurt", new HurtHappening(3));
            Add("confused", new BuffHappening(ConfusedBuff.Id, 30));
            Add("snail", new BuffHappening(SlowBuff.Id, 30));
            Add("broken", new BuffHappening(BrokenArmorBuff.Id, 30));
            Add("darkness", new DarknessHappening());
            Add("scourge_token", new ItemGiveHappening(() => Scourge.GenerateItemId()));
            Add("risk", new ItemGiveHappening(() => "bk:scourge_of_risk"));
            Add("double_trouble", new ItemGiveHappening(() => "bk:scourge_of_blood"));
            Add("rage", new BkRageHappening());
            Add("regular_tp", new TeleportHappening(RoomType.Regular, RoomType.Trap));
            Add("reset", new FloorResetHappening());
            Add("sudoku", new BombHappening());
            Add("items_hurt", new MakeItemsDamageUse());
            Add("scourged", new ScourgeHappening(3));
            Add("reroll_items", new RerollHappening(false, true));
            Add("reroll_weapon", new RerollHappening(true, false));
            Add("nerf", new ModifyMaxHpHappening(-2));
            Add("rob", new ModifyCoinsHappening(-10));
            Add("steal", new StealWeaponHappening());
            Add("bomb", new BombingHappening());
            Add("slide", new SlideHappening());

            // Good
            Add("give_random_consumable", new RandomItemHappening(ItemPool.Consumable));
            Add("invincible", new BuffHappening(InvincibleBuff.Id, 30));
            Add("heal", new HealHappening(2));
            Add("cleanse", new ScourgeHappening(-3));
            Add("chest", new ChestHappening());
            Add("gift", new ModifyCoinsHappening(10));

            // Neutral
            // Add("entrance_tp", new TeleportHappening(RoomType.Entrance));
            // Add("exit_tp", new TeleportHappening(RoomType.Exit, RoomType.Boss));
        }
Exemple #12
0
        public void RenderWindow()
        {
            ImGui.Separator();

            ImGui.Text($"Time: {Math.Floor(Time / 3600f)}h {Math.Floor(Time / 60f % 60f)}m {Math.Floor(Time % 60f)}s");
            ImGui.Text($"Won: {Won}");
            ImGui.Text($"Loop: {Run.Loop}");
            ImGui.Text($"Max Depth: {MaxDepth}");
            ImGui.Text($"Game Version: {GameVersion}");
            Run.CalculateScore();
            ImGui.Text($"Score: {Run.Score}");
            ImGui.Separator();

            if (ImGui.TreeNode("Items"))
            {
                foreach (var item in Items)
                {
                    ImGui.BulletText(item);
                }

                ImGui.TreePop();
            }

            if (ImGui.TreeNode("Banned items"))
            {
                foreach (var item in Banned)
                {
                    ImGui.BulletText(item);
                }

                ImGui.TreePop();
            }

            ImGui.Separator();
            ImGui.Text($"Coins Collected: {CoinsObtained}");
            ImGui.Text($"Keys Collected: {KeysObtained}");
            ImGui.Text($"Bombs Collected: {BombsObtained}");
            ImGui.Text($"Hearts Collected: {HeartsCollected}");
            ImGui.Text($"Heart Containers Collected: {MaxHealth}");
            ImGui.Separator();


            ImGui.Text($"Damage Taken: {DamageTaken}");
            ImGui.Text($"Damage Dealt: {DamageDealt}");
            ImGui.Text($"Mobs Killed: {MobsKilled}");
            ImGui.Text($"Rooms Explored: {RoomsExplored} / {RoomsTotal}");
            ImGui.Text($"Secret Rooms Explored: {SecretRoomsFound} / {SecretRoomsTotal}");
            ImGui.Separator();

            ImGui.Text($"Date Started: {Day} {Year}");
            ImGui.Text($"Tiles Walked: {TilesWalked}");
            ImGui.Text($"Pits Fallen: {PitsFallen}");
            ImGui.Text($"Bosses Defeated: {BossesDefeated}");
            ImGui.Text($"Spikes Triggered: {SpikesTriggered}");
            ImGui.Text($"Paintings Broke: {GlobalSave.GetInt("paintings_destroyed")}");

            ImGui.Separator();
            ImGui.Text($"Luck: {Run.Luck}");
            ImGui.Text($"Scourge: {Run.Scourge}");

            if (ImGui.TreeNode("Scourges"))
            {
                foreach (var curse in Scourge.Defined)
                {
                    var v = Scourge.IsEnabled(curse);

                    if (ImGui.Checkbox(curse, ref v))
                    {
                        if (v)
                        {
                            Scourge.Enable(curse);
                        }
                        else
                        {
                            Scourge.Disable(curse);
                        }
                    }
                }

                ImGui.TreePop();
            }
        }
Exemple #13
0
        public override bool HandleEvent(Event e)
        {
            if (e is LostSupportEvent)
            {
                if (GetComponent <HealthComponent>().Unhittable)
                {
                    return(true);
                }

                if (!GetComponent <BuffsComponent>().PitImmunity)
                {
                    GetComponent <HealthComponent>().ModifyHealth(-1, Run.Level);
                }


                for (var i = 0; i < 4; i++)
                {
                    var part = new ParticleEntity(Particles.Dust());

                    part.Position       = Center;
                    part.Particle.Scale = Rnd.Float(0.4f, 0.8f);
                    Area.Add(part);
                }
            }
            else if (e is RoomChangedEvent c)
            {
                if (c.New == null || Run.Level == null || Camera.Instance == null)
                {
                    return(base.HandleEvent(e));
                }

                if (c.New.Tagged[Tags.MustBeKilled].Count > 0)
                {
                    Audio.PlaySfx("level_door_shut");

                    foreach (var p in Area.Tagged[Tags.Player])
                    {
                        if (p.GetComponent <RoomComponent>().Room != c.New)
                        {
                            AnimationUtil.Poof(p.Center);
                            p.Center = Center;
                            AnimationUtil.Poof(p.Center);
                        }
                    }
                }

                ((InGameState)Engine.Instance.State).ResetFollowing();

                var pr = (PixelPerfectGameRenderer)Engine.Instance.StateRenderer;

                if (c.Old != null)
                {
                    if (Scourge.IsEnabled(Scourge.OfLost))
                    {
                        c.Old.Hide();
                    }

                    if (c.Old.Type == RoomType.DarkMarket || c.Old.Type == RoomType.Hidden)
                    {
                        pr.EnableClip = false;
                        c.Old.Hide(true);
                        InBuilding = false;
                        ((InGameState)Engine.Instance.State).UpdateRainVolume();
                    }
                }

                if (c.New.Type == RoomType.DarkMarket)
                {
                    Achievements.Unlock("bk:dark_market");
                }

                if (c.New.Type == RoomType.DarkMarket || c.New.Type == RoomType.Hidden)
                {
                    pr.EnableClip   = true;
                    pr.ClipPosition = new Vector2(c.New.X + 16, c.New.Y + 16);
                    pr.ClipSize     = new Vector2(c.New.Width - 16, c.New.Height - 32);
                    InBuilding      = true;
                    ((InGameState)Engine.Instance.State).UpdateRainVolume();
                }
                else
                {
                    pr.EnableClip = false;
                }

                if (c.New.Type == RoomType.Shop)
                {
                    Audio.PlaySfx("level_door_bell");
                }

                c.New.Discover();
                var level = Run.Level;

                if (InGameState.Ready)
                {
                    switch (c.New.Type)
                    {
                    case RoomType.Secret:
                    case RoomType.Special:
                    case RoomType.Shop:
                    case RoomType.SubShop:
                    case RoomType.Treasure: {
                        foreach (var door in c.New.Doors)
                        {
                            if (door.TryGetComponent <LockComponent>(out var component) && component.Lock is GoldLock)
                            {
                                if (!(c.New.Type == RoomType.Shop && ((door.Rooms[0] != null && door.Rooms[0].Type == RoomType.SubShop) ||
                                                                      (door.Rooms[1] != null && door.Rooms[1].Type == RoomType.SubShop))))
                                {
                                    component.Lock.SetLocked(false, this);
                                }
                            }
                        }

                        break;
                    }

                    case RoomType.OldMan:
                    case RoomType.Granny: {
                        if (c.New.Type == RoomType.OldMan)
                        {
                            GetComponent <StatsComponent>().SawDeal = true;
                        }

                        c.New.OpenHiddenDoors();

                        foreach (var r in Area.Tagged[Tags.Room])
                        {
                            var room = (Room)r;

                            if (room.Type == (c.New.Type == RoomType.OldMan ? RoomType.Granny : RoomType.OldMan))
                            {
                                room.CloseHiddenDoors();
                                break;
                            }
                        }

                        break;
                    }
                    }

                    if (c.New.Type == RoomType.Secret)
                    {
                        ExplosionMaker.CheckForCracks(level, c.New, this);
                    }
                }

                if (c.Old != null)
                {
                    if (c.Old.Type == RoomType.OldMan)
                    {
                        var found = false;

                        foreach (var p in c.Old.Tagged[Tags.Player])
                        {
                            if (p != this && p is Player)
                            {
                                found = true;

                                break;
                            }
                        }

                        if (!found)
                        {
                            c.Old.CloseHiddenDoors();
                        }
                    }
                    else if (c.Old.Type == RoomType.Treasure && Run.Type != RunType.BossRush && !Rnd.Chance(5))
                    {
                        var found = false;

                        foreach (var p in c.Old.Tagged[Tags.Player])
                        {
                            if (p != this && p is Player)
                            {
                                found = true;

                                break;
                            }
                        }

                        if (!found)
                        {
                            foreach (var door in c.Old.Doors)
                            {
                                var x = (int)Math.Floor(door.CenterX / 16);
                                var y = (int)Math.Floor(door.Bottom / 16);
                                var t = level.Get(x, y);

                                if (level.Get(x, y).Matches(TileFlags.Passable))
                                {
                                    var index = level.ToIndex(x, y);

                                    level.Set(index, level.Biome is IceBiome ? Tile.WallB : Tile.WallA);
                                    level.UpdateTile(x, y);
                                    level.ReCreateBodyChunk(x, y);
                                    level.LoadPassable();

                                    Camera.Instance.Shake(10);
                                }
                            }

                            c.Old.ApplyToEachTile((x, y) => {
                                if (Run.Level.Get(x, y).IsWall())
                                {
                                    return;
                                }

                                Timer.Add(() => {
                                    var part = new TileParticle();

                                    part.Top       = Run.Level.Tileset.WallTopADecor;
                                    part.TopTarget = Run.Level.Tileset.WallTopADecor;
                                    part.Side      = Run.Level.Tileset.FloorSidesD[0];
                                    part.Sides     = Run.Level.Tileset.WallSidesA[2];
                                    part.Tile      = Tile.WallA;

                                    part.X        = x * 16;
                                    part.Y        = y * 16;
                                    part.Target.X = x * 16;
                                    part.Target.Y = y * 16;
                                    part.TargetZ  = -8f;

                                    Area.Add(part);
                                }, Rnd.Float(0.5f));
                            });

                            foreach (var d in c.Old.Doors)
                            {
                                d.Done = true;
                            }

                            c.Old.Done = true;
                        }
                    }
                }

                // Darken the lighting in evil rooms
                if (c.New.Type == RoomType.OldMan || c.New.Type == RoomType.Spiked)
                {
                    Tween.To(0.7f, Lights.RadiusMod, x => Lights.RadiusMod = x, 0.3f);
                }
                else if (c.Old != null && (c.Old.Type == RoomType.OldMan || c.Old.Type == RoomType.Spiked))
                {
                    Tween.To(1f, Lights.RadiusMod, x => Lights.RadiusMod = x, 0.3f);
                }
            }
            else if (e is HealthModifiedEvent hm)
            {
                if (hm.Amount < 0)
                {
                    if ((hm.From is Mob m && m.HasPrefix) || (hm.From is creature.bk.BurningKnight k && k.InFight) || hm.From is BkOrbital)
                    {
                        hm.Amount = Math.Min(hm.Amount, -2);
                    }
                    else if (hm.Type != DamageType.Custom && hm.Type != DamageType.Explosive)
                    {
                        hm.Amount = Math.Max(-1, hm.Amount);
                    }
                }
            }
        public override void Paint(Level level)
        {
            if (LevelSave.BiomeGenerated is IceBiome)
            {
                var clip = Painter.Clip;
                Painter.Clip = null;
                Painter.Rect(level, this, 0, Tile.WallB);
                Painter.Clip = clip;
            }

            var t = Tiles.Pick(Tile.Chasm, Tile.WallA, Tile.WallB, Tile.Planks);

            if (Rnd.Chance())
            {
                Painter.Set(level, new Dot(Left + 1, Top + 1), t);
                Painter.Set(level, new Dot(Right - 1, Bottom - 1), t);
            }

            if (Rnd.Chance())
            {
                Painter.Set(level, new Dot(Right - 1, Top + 1), t);
                Painter.Set(level, new Dot(Left + 1, Bottom - 1), t);
            }

            if (Rnd.Chance(10 + Run.Scourge * 5))
            {
                var cn = GetCenter() * 16;
                var c  = Rnd.Int(2, 4);

                for (var i = 0; i < c; i++)
                {
                    var stand = new ScourgedStand();
                    level.Area.Add(stand);
                    stand.Center = cn + new Vector2(16 + (i - c / 2f) * 32, 8);

                    stand.SetItem(Items.CreateAndAdd(Scourge.GenerateItemId(), level.Area), stand);
                }

                return;
            }

            var center = GetCenter() * 16 + new Vector2(8);

            if (Rnd.Chance(5))
            {
                var chest = new ProtoChest();
                level.Area.Add(chest);
                chest.BottomCenter = center;

                return;
            }

            switch (Rnd.Int(GlobalSave.IsTrue(ShopNpc.Gobetta) ? 6 : 5))
            {
            case 0: {
                for (var i = 0; i < Rnd.Int(1, 3); i++)
                {
                    Items.CreateAndAdd("bk:heart", level.Area).Center = center;
                }

                break;
            }

            case 1: {
                for (var i = 0; i < Rnd.Int(1, 4); i++)
                {
                    Items.CreateAndAdd("bk:shield", level.Area).Center = center;
                }

                break;
            }

            case 2: {
                var stand = new ItemStand();
                level.Area.Add(stand);
                stand.BottomCenter = center;
                stand.SetItem(Items.CreateAndAdd(Items.Generate(ItemPool.Treasure), level.Area), null);

                break;
            }

            case 3: {
                var a = Rnd.Chance();
                var c = Rnd.Int(1, a ? 3 : 4);

                for (var i = 0; i < c; i++)
                {
                    var chest = a ? (Chest) new StoneChest() : new RedChest();
                    level.Area.Add(chest);
                    chest.BottomCenter = center - new Vector2((c / 2f - i) * 20, 0);
                }

                break;
            }

            case 4: {
                for (var i = 0; i < Rnd.Int(6, 12); i++)
                {
                    Items.CreateAndAdd("bk:coin", level.Area).Center = center;
                }

                break;
            }

            case 5: {
                Gobetta.Place(GetTileCenter() * 16 + new Vector2(8, 8), level.Area);
                break;
            }
            }
        }
Exemple #15
0
        public override void AddComponents()
        {
            base.AddComponents();

            Width  = 31;
            Height = 33;

            AddComponent(new AnimationComponent("emerald_golem"));
            AddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding, BodyType.Static));
            AddComponent(new RectBodyComponent(2, 17, 27, 16, BodyType.Static));

            AddComponent(new InteractableComponent(Interact)
            {
                CanInteract = e => !broken
            });

            GetComponent <DialogComponent>().Dialog.Voice = 15;

            Dialogs.RegisterCallback("eg_0", (d, c) => {
                if (broken)
                {
                    return(null);
                }

                if (((ChoiceDialog)d).Choice == 0)
                {
                    Timer.Add(() => {
                        GetComponent <DialogComponent>().StartAndClose(Locale.Get("eg_1"), 3);
                    }, 0.2f);

                    var inv = c.To.GetComponent <InventoryComponent>();
                    var a   = c.To.Area;

                    for (var i = 0; i < Amount; i++)
                    {
                        inv.Pickup(Items.CreateAndAdd("bk:emerald", a));
                    }

                    Timer.Add(() => {
                        inv.Pickup(Items.CreateAndAdd(Scourge.GenerateItemId(), a));
                    }, 1f);

                    Timer.Add(() => {
                        GetComponent <AnimationComponent>().Animate(() => {
                            Done = true;
                            Engine.Instance.Flash = 1f;
                            Camera.Instance.Shake(8);

                            for (var i = 0; i < 4; i++)
                            {
                                var part = new ParticleEntity(Particles.Dust());

                                part.Position       = Center + Rnd.Vector(-16, 16);
                                part.Particle.Scale = Rnd.Float(1f, 2f);
                                Run.Level.Area.Add(part);
                                part.Depth = 1;
                            }
                        });
                    }, 4f);

                    broken = true;
                    return(null);
                }
                else if (GlobalSave.IsTrue("bk:emerald_gun"))
                {
                    Timer.Add(() => {
                        GetComponent <DialogComponent>().StartAndClose(Locale.Get("eg_1"), 3);
                    }, 0.2f);

                    var inv = c.To.GetComponent <InventoryComponent>();
                    var a   = c.To.Area;

                    inv.Pickup(Items.CreateAndAdd("bk:emerald_gun", a));

                    Timer.Add(() => {
                        inv.Pickup(Items.CreateAndAdd(Scourge.GenerateItemId(), a));
                    }, 1f);

                    Timer.Add(() => {
                        GetComponent <AnimationComponent>().Animate(() => {
                            Done = true;
                            Engine.Instance.Flash = 1f;
                            Camera.Instance.Shake(8);

                            for (var i = 0; i < 4; i++)
                            {
                                var part = new ParticleEntity(Particles.Dust());

                                part.Position       = Center + Rnd.Vector(-16, 16);
                                part.Particle.Scale = Rnd.Float(1f, 2f);
                                Run.Level.Area.Add(part);
                                part.Depth = 1;
                            }
                        });
                    }, 4f);

                    broken = true;
                    return(null);
                }

                return(null);
            });

            Subscribe <RoomChangedEvent>();
        }
Exemple #16
0
        private void RenderHealthBar(bool pad)
        {
            var red    = Player.GetComponent <HealthComponent>();
            var phases = red.Phases;

            if (Scourge.IsEnabled(Scourge.OfRisk))
            {
                Graphics.Render(question, new Vector2(8 + (int)((4 + ItemSlot.Source.Width) * (activeSlot.ActivePosition + 1)), 11));

                if (phases > 0)
                {
                    Graphics.Print($"x{phases}", Font.Small, new Vector2(8 + question.Width + 4 + (int)((4 + ItemSlot.Source.Width) * (activeSlot.ActivePosition + 1)), 12));
                }

                return;
            }

            var hearts   = Player.GetComponent <HeartsComponent>();
            var totalRed = red.Health;

            if (lastRed > totalRed)
            {
                lastRed = totalRed;
            }
            else if (lastRed < totalRed)
            {
                lastRed = Math.Min(totalRed, lastRed + Engine.Delta * 30);
            }

            var r       = (int)lastRed;
            var maxRed  = red.MaxHealth;
            var hurt    = red.InvincibilityTimer > 0;
            var shields = hearts.ShieldHalfs;
            var bombs   = (int)hearts.Bombs;
            var dbombs  = bombs * 2;
            var mbombs  = (int)hearts.BombsMax;
            var mdbombs = mbombs * 2;

            var n  = r;
            var jn = maxRed;

            if (jn % 2 == 1)
            {
                jn++;
            }

            var vegan = Settings.Vegan;

            for (var i = 0; i < maxRed; i += 2)
            {
                var region = hurt ? (vegan ? veganchangedHeartBackground : changedHeartBackground) : (vegan ? veganHeartBackground : HeartBackground);

                if (i == maxRed - 1)
                {
                    region = hurt ? (vegan ? veganchangedHalfHeartBackground : changedHalfHeartBackground) : (vegan ? veganhalfHeartBackground : halfHeartBackground);
                }

                Graphics.Render(region, GetHeartPosition(pad, i, true));
            }

            for (var i = jn; i < maxRed + mdbombs; i += 2)
            {
                var region = hurt ? ChangedBombBg : BombBg;

                Graphics.Render(region, GetHeartPosition(pad, i, true) + new Vector2(0, -1));
            }

            for (var i = jn + mdbombs; i < maxRed + shields + mdbombs; i += 2)
            {
                var region = hurt ? changedShieldBackground : ShieldBackground;

                if (i == maxRed + shields - 1)
                {
                    region = hurt ? changedHalfShieldBackground : halfShieldBackground;
                }

                Graphics.Render(region, GetHeartPosition(pad, i, true));
            }

            for (var j = 0; j < n; j++)
            {
                var h = j % 2 == 0;
                Graphics.Render(h ? (vegan ? veganHalfHeart : HalfHeart) : (vegan ? veganHeart : Heart), GetHeartPosition(pad, j) + (h ? Vector2.Zero : new Vector2(-1, 0)));
            }

            for (var j = jn; j < maxRed + dbombs; j += 2)
            {
                Graphics.Render(Bomb, GetHeartPosition(pad, j) + new Vector2(0, -1));
            }

            if (phases > 0)
            {
                Graphics.Print($"x{phases}", Font.Small, GetHeartPosition(pad, Math.Min(15, maxRed + shields + bombs)) + new Vector2(4, -2));
            }
        }