public void OpenHiddenDoors() { var level = Run.Level; foreach (var door in Doors) { var x = (int)Math.Floor(door.CenterX / 16); var y = (int)Math.Floor(door.CenterY / 16); var t = level.Get(x, y); if (t == Tile.WallA || t == Tile.WallB) { var index = level.ToIndex(x, y); level.Set(index, Type == RoomType.OldMan ? Tile.EvilFloor : Tile.GrannyFloor); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); level.LoadPassable(); ExplosionMaker.LightUp(x * 16 + 8, y * 16 + 8); Level.Animate(Area, x, y); } } }
public override void Update(float dt) { base.Update(dt); var d = Self.DistanceTo(Self.Target); if (d > 48f) { Self.Become <RunState>(); return; } if (T >= 0.66f) { Self.Done = true; Self.Exploded = true; AudioEmitterComponent.Dummy(Self.Area, Self.Center).EmitRandomized("mob_archeolog_explosion", sz: 0.2f); ExplosionMaker.Make(Self, 48f); } var flash = T % 0.33 < 0.15f; if (flash && !lastFlash) { Self.GetComponent <AudioEmitterComponent>().Emit("mob_spelunker_beep", 1f, T); } lastFlash = flash; Self.GetComponent <MobAnimationComponent>().Flash = flash; }
protected override void AnimateDeath(Entity e, bool timeout = false) { base.AnimateDeath(e, timeout); ExplosionMaker.Make(this, damageOwner: HurtOwner); exploded = true; }
public void Explode() { OnDeath?.Invoke(this); Done = true; var r = GetComponent <ExplodeComponent>().Radius; ExplosionMaker.Make(this, r, scale: r / 32f); }
public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce) { if (!Rnd.Chance(chance)) { return(base.HandleEvent(e)); } ExplosionMaker.CheckForCracks(Run.Level, rce.New, rce.Who); } return(base.HandleEvent(e)); }
public override void Update(float dt) { base.Update(dt); Timer -= dt; if (Timer <= 0) { if (Entity is Bomb b) { b.Explode(); return; } Entity.Done = true; ExplosionMaker.Make(Entity, Radius); } }
public override void Init() { base.Init(); var p = new ProjectilePattern(CircleWithCenterProjectilePattern.Make(14f, 3)) { Position = Self.Center }; var bullet = Projectile.Make(Self, "huge", Self.AngleTo(Self.Target), 7); bullet.OnDeath = (pr, e, t) => { p.Kill(); ExplosionMaker.Make(pr.Owner, 16, false, new Vec2(pr.Center)); for (var i = 0; i < SmallCount; i++) { var b = Projectile.Make(Self, "green_small", (float)(((float)i) / SmallCount * Math.PI * 2), 6, true, 1, pr); b.Center = pr.Center; b.AddLight(32f, Projectile.GreenLight); } }; bullet.CanBeReflected = false; bullet.CanBeBroken = false; p.Add(bullet); for (var j = 0; j < OrbiterCount; j++) { var b = Projectile.Make(Self, "green_small"); b.CanBeBroken = false; b.CanBeReflected = false; b.AddLight(32f, Projectile.GreenLight); p.Add(b); } p.Launch(Self.AngleTo(Self.Target), 20); Self.Area.Add(p); }
private void ApplyBuff(Projectile projectile, string buff, bool explosive) { if (explosive) { projectile.Color = ProjectileColor.Brown; projectile.OnDeath += (p, en, t) => { ExplosionMaker.Make(p, 32, false, damage: 4, scale: 0.5f); }; } if (buff != null) { if (!BuffRegistry.All.TryGetValue(buff, out var info)) { Log.Error($"Unknown buff {buff}"); return; } projectile.Color = info.Effect.GetColor(); projectile.OnHurt += (p, e) => { if (e.TryGetComponent <BuffsComponent>(out var buffs)) { var b = BuffRegistry.Create(buff); if (InfiniteBuff) { b.Infinite = true; } else { b.TimeLeft = b.Duration = BuffDuration; } buffs.Add(b); } }; } }
private static void CheckMine(Level level, int x, int y) { if (level.Get(x, y) == Tile.Planks) { level.Set(x, y, Tile.Ember); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); Camera.Instance.ShakeMax(3); Level.Animate(level.Area, x, y); } else if (level.Get(x, y, true).Matches(Tile.Rock, Tile.TintedRock, Tile.MetalBlock)) { level.Set(x, y, Tile.Ember); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); Camera.Instance.ShakeMax(3); ExplosionMaker.BreakRock(level, new Dot(x * 16 + 8, y * 16 + 8), x, y, level.Get(x, y, true)); } }
public void Explode() { if (Done) { return; } Done = true; ExplosionMaker.Make(this, 32f); var who = trigger; var count = 0; while (who != null && who is ExplodingBarrel b) { who = b.trigger; count++; } if (count >= 2) { Achievements.Unlock("bk:boom"); } }
static ProjectileRegistry() { Add("skull", skull => { skull.NearDeath += p => { var c = new AudioEmitterComponent { DestroySounds = false }; p.AddComponent(c); c.Emit("mob_oldking_explode"); }; skull.OnDeath += (p, e, t) => { for (var i = 0; i < 8; i++) { var bullet = Projectile.Make(p.Owner, "small", ((float)i) / 4 * (float)Math.PI, (i % 2 == 0 ? 2 : 1) * 4 + 3); bullet.CanBeReflected = false; bullet.Center = p.Center; } }; skull.Controller += TargetProjectileController.Make(null, 0.5f); skull.Range = 5f; skull.IndicateDeath = true; skull.CanBeReflected = false; skull.GetComponent <ProjectileGraphicsComponent>().IgnoreRotation = true; }); Add("disk", p => { CollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is HalfProjectileLevel ? CollisionResult.Disable : CollisionResult.Default); p.BounceLeft += 10; p.CanHitOwner = true; p.GetComponent <CircleBodyComponent>().Body.AngularVelocity = 10f; }); Add("what", p => { p.Controller += WhatController.Make(); p.GetComponent <CircleBodyComponent>().Body.AngularVelocity = 10f; }); Add("soap", p => { p.Controller += SlowdownProjectileController.Make(2); }); Add("grenade", p => { CollisionFilterComponent.Add(p, (entity, with) => { if (with is Mob) { p.BounceLeft = 0; return(CollisionResult.Enable); } return(CollisionResult.Default); }); p.Controller += SlowdownProjectileController.Make(1); p.BreaksFromWalls = false; p.OnDeath += (pr, e, t) => { ExplosionMaker.Make(pr, 16, damage: 8); }; p.Controller += (pr, dt) => { if (pr.T >= 3f) { pr.Break(); } }; }); Add("missile", p => { CollisionFilterComponent.Add(p, (entity, with) => { if (with is Mob) { p.BounceLeft = 0; return(CollisionResult.Enable); } if (with is Prop) { return(CollisionResult.Disable); } return(CollisionResult.Default); }); p.Controller += TargetProjectileController.Make(null, 0.5f); p.Controller += SmokeProjectileController.Make(); p.OnDeath += (pr, e, t) => { ExplosionMaker.Make(pr, 32); }; }); Add("shotgun", p => { p.Controller += SlowdownProjectileController.Make(1); p.BounceLeft += 1; }); Add("follower", p => { CollisionFilterComponent.Add(p, (entity, with) => { if (with is Mob) { p.BounceLeft = 0; return(CollisionResult.Enable); } if (with is Prop) { return(CollisionResult.Disable); } return(CollisionResult.Default); }); p.Controller += TargetProjectileController.MakeCursor(); p.Controller += SmokeProjectileController.Make(); p.OnDeath += (pr, e, t) => { ExplosionMaker.Make(pr, 32); }; }); Add("flak", p => { CollisionFilterComponent.Add(p, (entity, with) => { if (with is Mob) { p.BounceLeft = 0; return(CollisionResult.Enable); } return(CollisionResult.Default); }); p.Controller += SlowdownProjectileController.Make(0.5f); p.OnDeath += (pr, e, t) => { for (var i = 0; i < 8; i++) { var pr2 = Projectile.Make(pr.Owner, "shot", (float)i / 8 * (float)Math.PI * 2, 8, true, 0, null, 0.8f); pr2.Center = pr.Center; pr2.Controller += SlowdownProjectileController.Make(1); } }; p.Controller += (pr, dt) => { if (pr.T >= 1f) { pr.Break(); } }; }); Add("crash", p => { p.Controller += HsvProjectileController.Make(); p.OnDeath += (pr, ee, t) => { if (pr.T < 0.1f) { return; } for (var i = 0; i < 8; i++) { var p2 = Projectile.Make(pr.Owner, "square", (float)i / 8 * (float)Math.PI * 2, 8, true, 0, null, 0.8f); p2.Center = pr.Center; p2.Controller += HsvProjectileController.Make(1, pr.T); p2.OnDeath += (pr2, eee, t2) => { if (pr2.T < 0.1f) { return; } for (var j = 0; j < 8; j++) { var p3 = Projectile.Make(pr.Owner, "square", (float)j / 8 * (float)Math.PI * 2, 12, true, 0, null, 0.6f); p3.Center = pr2.Center; p3.Controller += HsvProjectileController.Make(1, p2.T); p3.OnDeath += (pr4, eeee, t4) => { if (pr4.T < 0.1f) { return; } for (var k = 0; k < 8; k++) { var p5 = Projectile.Make(pr.Owner, "square", (float)k / 8 * (float)Math.PI * 2, 24, true, 0, null, 0.3f); p5.Center = pr4.Center; p5.Controller += HsvProjectileController.Make(1, pr4.T); } }; } }; } }; }); Add("duck", p => { CollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is Prop ? CollisionResult.Disable : CollisionResult.Default); }); Add("portal", p => { p.Center = p.Owner.GetComponent <CursorComponent>().Cursor.GamePosition; p.GetAnyComponent <BodyComponent>().Velocity *= -1; }); Add("axe", p => { CollisionFilterComponent.Add(p, (entity, with) => ((with is Creature && with != p.Owner) || ((Projectile)entity).BounceLeft == 0) ? CollisionResult.Disable : CollisionResult.Default); var ts = Timer.Add(() => { p.Item.Renderer.Hidden = false; foreach (var u in p.Item.Uses) { if (u is SimpleShootUse ss) { ss.ProjectileDied = true; break; } } }, 3f); p.Range = 5; p.PreventSpectralBreak = true; p.OnCollision = (projectile, e) => { if (Run.Level.Biome is IceBiome && e is ProjectileLevelBody lvl) { if (lvl.Break(projectile.CenterX, projectile.CenterY)) { AudioEmitterComponent.Dummy(projectile.Area, projectile.Center).EmitRandomizedPrefixed("level_snow_break", 3); } } if (projectile.BounceLeft == 0) { if (e == projectile.Owner) { projectile.Item.Renderer.Hidden = false; projectile.Break(); foreach (var u in projectile.Item.Uses) { if (u is SimpleShootUse ss) { ss.ProjectileDied = true; break; } } } else if (!(e is Mob)) { return(true); } } else if (projectile.BreaksFrom(e, null)) { if (e is Painting || e is BreakableProp || e is ExplodingBarrel || e.HasComponent <HealthComponent>()) { projectile.BounceLeft++; } else { var b = projectile.GetComponent <RectBodyComponent>().Body; b.LinearVelocity *= -1; projectile.BounceLeft = 0; projectile.EntitiesHurt.Clear(); projectile.Controller += ReturnProjectileController.Make(projectile.Owner); var pi = projectile.OnDeath; projectile.OnDeath = (pr, ee, t) => { pr.Item.Renderer.Hidden = false; foreach (var u in pr.Item.Uses) { if (u is SimpleShootUse ss) { ss.ProjectileDied = true; break; } } ts.Cancel(); pr.Owner.GetComponent <AudioEmitterComponent>().EmitRandomized("item_axe_catch"); }; pi?.Invoke(projectile, e, false); return(true); } } return(false); }; p.BounceLeft = 1; p.DieOffscreen = false; p.Rotates = true; p.Item.Renderer.Hidden = true; });
private bool Interact(Entity e) { Animate(); var p = e ?? LocalPlayer.Locate(Area); var active = p.GetComponent <ActiveItemComponent>(); if (active.Item == null) { GetComponent <DialogComponent>().StartAndClose("charger_0", 3); AnimationUtil.ActionFailed(); return(true); } if (active.Item.Delay <= 0.02f) { GetComponent <DialogComponent>().StartAndClose("charger_1", 3); AnimationUtil.ActionFailed(); return(true); } if (e != null) { var component = p.GetComponent <ConsumablesComponent>(); if (component.Coins == 0) { if (noMoneyAttempt == 0) { GetComponent <DialogComponent>().StartAndClose("charger_2", 3); } else if (noMoneyAttempt == 1) { GetComponent <DialogComponent>().StartAndClose("charger_3", 3); } else { var hp = p.GetComponent <HealthComponent>(); hp.ModifyHealth(-1, this); GetComponent <DialogComponent>().StartAndClose($"charger_{(hp.HasNoHealth ? 5 : 4)}", 3); } noMoneyAttempt++; AnimationUtil.ActionFailed(); return(true); } noMoneyAttempt = 0; component.Coins -= 1; } timesUsed += e == null ? 4 : 1; active.Charge(Rnd.Int(1, 3)); Audio.PlaySfx("item_charge"); if (Rnd.Float(100) < timesUsed * 2 - Run.Luck * 0.5f) { Break(false); ExplosionMaker.Make(p); return(true); } return(false); }
protected override bool HandleDeath(DiedEvent d) { ExplosionMaker.Make(this, 16); return(base.HandleDeath(d)); }
public override void Use(Entity entity, Item item) { base.Use(entity, item); ExplosionMaker.Make(entity); }
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 AnimateDeath(DiedEvent d) { base.AnimateDeath(d); ExplosionMaker.Make(this); OnDeath?.Invoke(); }
public override void Update(float dt) { base.Update(dt); if (!added) { added = true; var x = (int)Math.Floor(CenterX / 16); var y = (int)Math.Floor(Bottom / 16); if (Run.Level.IsInside(x, y)) { Run.Level.Passable[Run.Level.ToIndex(x, y)] = false; } } var state = GetComponent <StateComponent>(); if (state.StateInstance is OpenState && Colliding.Count == 0 && !OpenByDefault) { lastCollisionTimer -= dt; if (lastCollisionTimer <= 0) { HandleEvent(new DoorClosedEvent { Who = this }); state.Become <ClosingState>(); } } if (Rooms == null) { Rooms = new Room[2]; var i = 0; var pad = 4; var rc = new Rectangle((int)(X + pad), (int)Y, (int)(Width - pad * 2), (int)Height); foreach (var room in Area.Tagged[Tags.Room]) { if (room.Overlaps(rc)) { var r = (Room)room; Rooms[i] = r; r.Doors.Add(this); i++; if (i == 2) { break; } } } } if (Rooms != null && !lit) { var found = false; foreach (var rm in Rooms) { if (rm != null && rm.Tagged[Tags.Player].Count > 0) { found = true; break; } } if (found) { foreach (var rm in Rooms) { if (rm != null && (rm.Type == RoomType.OldMan || rm.Type == RoomType.Granny)) { return; } } lit = true; ExplosionMaker.LightUp(CenterX, CenterY); } } }
public override void Use(Entity entity, Item item) { ExplosionMaker.CheckForCracks(Run.Level, entity.GetComponent <RoomComponent>().Room, entity); }