protected internal override void OnZap(int cell) { var localLevel = Level; var n = localLevel + 2; if (Actor.FindChar(cell) != null && Ballistica.Distance > 2) { cell = Ballistica.Trace[Ballistica.Distance - 2]; } var passable = BArray.or(levels.Level.passable, levels.Level.avoid, null); foreach (var actor in Actor.All.OfType <Character>()) { passable[(actor).pos] = false; } PathFinder.BuildDistanceMap(cell, passable, n); var dist = 0; if (Actor.FindChar(cell) != null) { PathFinder.Distance[cell] = int.MaxValue; dist = 1; } float lifespan = localLevel + 3; sheepLabel: for (var i = 0; i < n; i++) { do { for (var j = 0; j < levels.Level.Length; j++) { if (PathFinder.Distance[j] != dist) { continue; } var sheep = new Sheep(); sheep.Lifespan = lifespan; sheep.pos = j; GameScene.Add(sheep); Dungeon.Level.MobPress(sheep); CellEmitter.Get(j).Burst(Speck.Factory(Speck.WOOL), 4); PathFinder.Distance[j] = int.MaxValue; goto sheepLabel; } dist++; } while (dist < n); } }
protected internal virtual void Evolve() { var notBlocking = BArray.not(levels.Level.solid, null); for (var i = 1; i < Height - 1; i++) { var from = i * Width + 1; var to = from + Width - 2; for (var pos = from; pos < to; pos++) { if (notBlocking[pos]) { var count = 1; var sum = Cur[pos]; if (notBlocking[pos - 1]) { sum += Cur[pos - 1]; count++; } if (notBlocking[pos + 1]) { sum += Cur[pos + 1]; count++; } if (notBlocking[pos - Width]) { sum += Cur[pos - Width]; count++; } if (notBlocking[pos + Width]) { sum += Cur[pos + Width]; count++; } var value = sum >= count ? (sum / count) - 1 : 0; Off[pos] = value; Volume += value; } else { Off[pos] = 0; } } } }
public static void Observe() { if (Level == null) { return; } Level.UpdateFieldOfView(Hero); Array.Copy(Level.fieldOfView, 0, Visible, 0, Visible.Length); BArray.or(Level.visited, Visible, Level.visited); GameScene.AfterObserve(); }
public override void Activate(Character ch) { base.Activate(ch); PathFinder.BuildDistanceMap(Pos, BArray.not(Level.losBlocking, null), 1); var fire = (Fire)Dungeon.Level.Blobs[typeof(Fire)]; for (var i = 0; i < Level.Length; i++) { if (PathFinder.Distance[i] < int.MaxValue) { Freezing.Affect(i, fire); } } }
protected internal override void OnZap(int cell) { Sample.Instance.Play(Assets.SND_ROCKS); var localLevel = Level; Ballistica.Distance = Math.Min(Ballistica.Distance, 8 + localLevel); var size = 1 + localLevel / 3; PathFinder.BuildDistanceMap(cell, BArray.not(levels.Level.solid, null), size); for (var i = 0; i < levels.Level.Length; i++) { int d = PathFinder.Distance[i]; if (d >= int.MaxValue) { continue; } var ch = Actor.FindChar(i); if (ch != null) { ch.Sprite.Flash(); ch.Damage(pdsharp.utils.Random.Int(2, 6 + (size - d) * 2), this); if (ch.IsAlive && pdsharp.utils.Random.Int(2 + d) == 0) { Buff.Prolong <Paralysis>(ch, pdsharp.utils.Random.IntRange(2, 6)); } } CellEmitter.Get(i).Start(Speck.Factory(Speck.ROCK), 0.07f, 3 + (size - d)); Camera.Main.Shake(3, 0.07f * (3 + (size - d))); } if (CurUser.IsAlive) { return; } Dungeon.Fail(Utils.Format(ResultDescriptions.WAND, name, Dungeon.Depth)); GLog.Negative("You killed yourself with your own Wand of Avalanche..."); }
protected internal override void Shatter(int cell) { PathFinder.BuildDistanceMap(cell, BArray.not(Level.losBlocking, null), Distance); var fire = (Fire)Dungeon.Level.Blobs[typeof(Fire)]; for (var i = 0; i < Level.Length; i++) { if (PathFinder.Distance[i] < int.MaxValue) { Freezing.Affect(i, fire); } } splash(cell); Sample.Instance.Play(Assets.SND_SHATTER); SetKnown(); }
public static int Flee(Character ch, int cur, int from, bool[] pass, bool[] visible) { if (ch.Flying) { BArray.or(pass, Level.avoid, Passable); } else { Array.Copy(pass, 0, Passable, 0, Level.Length); } foreach (var pos in Actor.All.OfType <Character>().Select(c => c.pos).Where(pos => visible[pos])) { Passable[pos] = false; } Passable[cur] = true; return(PathFinder.GetStepBack(cur, from, Passable)); }
public static int FindPath(Character ch, int from, int to, bool[] pass, bool[] visible) { if (Level.Adjacent(from, to)) { return(Actor.FindChar(to) == null && (pass[to] || Level.avoid[to]) ? to : -1); } if (ch.Flying || ch.Buff <Amok>() != null) { BArray.or(pass, Level.avoid, Passable); } else { Array.Copy(pass, 0, Passable, 0, Level.Length); } foreach (int pos in Actor.All.OfType <Character>().Select(actor => (actor).pos).Where(pos => visible[pos])) { Passable[pos] = false; } return(PathFinder.GetStep(from, to, Passable)); }
/// <summary> /// Helper method to get a random element in a BSON array. /// </summary> public BValue ArrayElement(BArray props, int?min = null, int?max = null) { var r = Number(min: min ?? 0, max: max - 1 ?? props.Count - 1); return(props[r]); }
protected internal override void Shatter(int cell) { PathFinder.BuildDistanceMap(cell, BArray.not(Level.losBlocking, null), DISTANCE); var procd = false; Blob[] blobs = { Dungeon.Level.Blobs[typeof(ToxicGas)], Dungeon.Level.Blobs[typeof(ParalyticGas)] }; foreach (var blob in blobs) { if (blob == null) { continue; } for (var i = 0; i < Level.Length; i++) { if (PathFinder.Distance[i] >= int.MaxValue) { continue; } var value = blob.Cur[i]; if (value <= 0) { continue; } blob.Cur[i] = 0; blob.Volume -= value; procd = true; CellEmitter.Get(i).Burst(Speck.Factory(Speck.DISCOVER), 1); } } var heroAffected = PathFinder.Distance[Dungeon.Hero.pos] < int.MaxValue; if (procd) { splash(cell); Sample.Instance.Play(Assets.SND_SHATTER); SetKnown(); if (heroAffected) { GLog.Positive(TXT_FRESHNESS); } } else { base.Shatter(cell); if (!heroAffected) { return; } GLog.Information(TXT_FRESHNESS); SetKnown(); } }
public override void Paint(Level level) { var w = GetWidth(); var h = GetHeight(); var old = Painter.Clip; Painter.Clip = null; Painter.Fill(level, this, Wall); Painter.Clip = old; Painter.FillEllipse(level, this, 3, Tile.FloorA); Painter.FillEllipse(level, this, (int)(Math.Min(w, h) / 2f - 2), Tile.FloorD); var r = GetCenterRect(); PaintTunnel(level, Tile.FloorA, r, true); PaintTunnel(level, Tile.FloorD, r); Pass((x, y) => { var t = level.Get(x, y); if (t != Tile.FloorD || Rnd.Chance(30)) { if (t == Tile.WallA && Rnd.Chance(10)) { Painter.Set(level, x, y, Tile.FloorA); } return; } var sz = Rnd.Int(2, 4); for (var xx = -sz; xx <= sz; xx++) { for (var yy = -sz; yy <= sz; yy++) { if (level.Get(x + xx, y + yy) != Tile.FloorD) { Painter.Set(level, x + xx, y + yy, Rnd.Chance(30) ? Tile.WallA : Tile.FloorA); } } } }); var array = new byte[w, h]; var oldArray = new byte[w, h]; Pass((x, y) => { var t = level.Get(x, y); if (t == Tile.FloorA && Rnd.Float() > 0.55f - (float)(Math.Cos(x / 16f) * 0.02f + Math.Cos(y / 16f) * 0.1f)) { t = Tile.WallA; Painter.Set(level, x, y, t); } var v = t == Tile.FloorA ? 0 : 1; if (t == Tile.FloorD) { v = 2; } array[x - Left, y - Top] = (byte)v; oldArray[x - Left, y - Top] = (byte)v; }); for (var i = 0; i < 5; i++) { for (var x = 0; x < w; x++) { for (var y = 0; y < h; y++) { var c = oldArray[x, y]; var n = 0; foreach (var d in MathUtils.AllDirections) { var xx = x + (int)d.X; var yy = y + (int)d.Y; if (xx < 0 || xx >= w || yy < 0 || yy >= h) { n++; continue; } if (oldArray[xx, yy] == 1) { n++; } } if (c != 2) { if (n < DeathCondition) { c = 0; } else if (n > BirthCondition) { c = 1; } } array[x, y] = c; } } for (var x = 0; x < w; x++) { for (var y = 0; y < h; y++) { oldArray[x, y] = array[x, y]; } } } Action <int, int> fill = null; var queue = new Queue <Dot>(); var m = 0; fill = (x, y) => { if (x < 0 || y < 0 || x >= w || y >= h) { return; } var v = array[x, y]; if (v == 1 || v == 3) { return; } m++; array[x, y] = 3; queue.Enqueue(new Dot(x - 1, y)); queue.Enqueue(new Dot(x + 1, y)); queue.Enqueue(new Dot(x, y - 1)); queue.Enqueue(new Dot(x, y + 1)); }; var painted = false; foreach (var dr in Connected.Values) { var st = new Dot(dr.X, dr.Y); if (dr.X == Left) { st = new Dot(dr.X + 1, dr.Y); } else if (dr.X == Right) { st = new Dot(dr.X - 1, dr.Y); } else if (dr.Y == Top) { st = new Dot(dr.X, dr.Y + 1); } else if (dr.Y == Bottom) { st = new Dot(dr.X, dr.Y - 1); } fill(st.X - Left, st.Y - Top); if (queue.Count != 0) { painted = true; break; } } if (!painted) { Log.Error("Did not spot a spot in the jungle room!"); Paint(level); return; } while (queue.Count > 0) { var d = queue.Dequeue(); fill(d.X, d.Y); } var start = 0; var ww = GetWidth(); var hh = GetHeight(); Func <int, int, int> toIndex = (x, y) => (x - Left) + (y - Top) * ww; foreach (var d in Connected.Values) { if (d.X == Left) { start = toIndex(d.X + 1, d.Y); } else if (d.X == Right) { start = toIndex(d.X - 1, d.Y); } else if (d.Y == Top) { start = toIndex(d.X, d.Y + 1); } else if (d.Y == Bottom) { start = toIndex(d.X, d.Y - 1); } } Pass((x, y) => { if (x > Left && x < Right && y > Top && y < Bottom) { Painter.Set(level, x, y, array[x - Left, y - Top] == 3 ? Floor : Wall); } }); var patch = new bool[ww * hh]; for (var y = 0; y < hh; y++) { for (var x = 0; x < ww; x++) { patch[y * ww + x] = !level.Get(Left + x, Top + y).IsPassable(); } } PathFinder.SetMapSize(ww, hh); PathFinder.BuildDistanceMap(start, BArray.Not(patch, null)); var valid = true; for (var i = 0; i < patch.Length; i++) { if (!patch[i] && PathFinder.Distance[i] == Int32.MaxValue) { valid = false; break; } } // level.Set(Left + start % ww, Top + start / ww, Tile.Cobweb); PathFinder.SetMapSize(level.Width, level.Height); if (!valid) { Log.Error("Failed to build path"); Paint(level); return; } patch = Patch.GenerateWithNoise(w, h, Rnd.Float(10000), 0.25f, 0.1f); if (Floor2 != Floor) { Pass((x, y) => { if (level.Get(x, y) == Floor && patch[(x - Left) + (y - Top) * w]) { Painter.Set(level, x, y, Floor2); } }); } }
protected void Setup(Level level, RoomDef room, float fill, int clustering, bool ensurePath) { Run.Level = level; var w = room.GetWidth() - 2; var h = room.GetHeight() - 2; if (ensurePath) { PathFinder.SetMapSize(w, h); var valid = false; var attempt = 0; do { Patch = BurningKnight.level.Patch.Generate(w, h, fill, clustering); var start = 0; foreach (var d in room.Connected.Values) { if (d.X == room.Left) { start = ToIndex(room, d.X + 1, d.Y); Patch[ToIndex(room, d.X + 1, d.Y)] = false; Patch[ToIndex(room, d.X + 2, d.Y)] = false; } else if (d.X == room.Right) { start = ToIndex(room, d.X - 1, d.Y); Patch[ToIndex(room, d.X - 1, d.Y)] = false; Patch[ToIndex(room, d.X - 2, d.Y)] = false; } else if (d.Y == room.Top) { start = ToIndex(room, d.X, d.Y + 1); Patch[ToIndex(room, d.X, d.Y + 1)] = false; Patch[ToIndex(room, d.X, d.Y + 2)] = false; } else if (d.Y == room.Bottom) { start = ToIndex(room, d.X, d.Y - 1); Patch[ToIndex(room, d.X, d.Y - 1)] = false; Patch[ToIndex(room, d.X, d.Y - 2)] = false; } } PathFinder.BuildDistanceMap(start, BArray.Not(Patch, null)); valid = true; for (var i = 0; i < Patch.Length; i++) { if (!Patch[i] && PathFinder.Distance[i] == Int32.MaxValue) { valid = false; break; } } if (!valid && fill > 0.1f) { fill -= 0.01f; } } while (attempt++ < 1000 && !valid); if (!valid) { Log.Error("Failed to generate patch"); for (var i = 0; i < Patch.Length; i++) { Patch[i] = false; } } PathFinder.SetMapSize(level.Width, level.Height); } else { Patch = BurningKnight.level.Patch.Generate(w, h, fill, clustering); } }
public override void Paint(Level level, RoomDef room, Rect inside) { var fill = 0.25f + (room.GetWidth() * room.GetHeight()) / 1024f; var s = Rnd.Chance(); bool[] oldPatch = null; if (s) { Setup(level, room, fill, 4, true); CleanDiagonalEdges(room); PaintPatch(level, room, Tiles.RandomSolid()); oldPatch = ArrayUtils.Clone(Patch); } SimplePaint(level, room); if (s) { PathFinder.SetMapSize(room.GetWidth() - 2, room.GetHeight() - 2); var start = 0; foreach (var d in room.Connected.Values) { if (d.X == room.Left) { start = ToIndex(room, d.X + 1, d.Y); } else if (d.X == room.Right) { start = ToIndex(room, d.X - 1, d.Y); } else if (d.Y == room.Top) { start = ToIndex(room, d.X, d.Y + 1); } else if (d.Y == room.Bottom) { start = ToIndex(room, d.X, d.Y - 1); } } for (var i = 0; i < Patch.Length; i++) { if (oldPatch[i]) { Patch[i] = true; } } PathFinder.BuildDistanceMap(start, BArray.Not(Patch, null)); var valid = true; for (var i = 0; i < Patch.Length; i++) { if (!Patch[i] && PathFinder.Distance[i] == Int32.MaxValue) { valid = false; break; } } PathFinder.SetMapSize(level.Width, level.Height); if (!valid) { Painter.Fill(level, room, 1, Tiles.RandomFloor()); SimplePaint(level, room); } } }