public OccupationType CheckPosition(Pos2D pos, ChessPiece inquisitor) { // broad check if on board: if (pos.x < 0 || pos.x > sizex - 1 || pos.y < 0 || pos.y > sizey - 1) { return(OccupationType.OUT); } // check if field is accesseble: if (!chessFields[pos.x, pos.y].accessible) { return(OccupationType.NONACCESS); } // loop over other pieces: foreach (ChessAgent a in chessAgents) { foreach (ChessPiece cp in a.ChessPieces) { if (cp.pos == pos) { if (inquisitor != null && cp.agent == inquisitor.agent) { return(OccupationType.SAMEPARTY); } else { return(OccupationType.ENEMY); } } } } return(OccupationType.FREE); }
public void LoadDefault() { plane.gameObject.SetActive(true); Draw(planeWidth, planeHeight, maskWidth, maskHeight); p1 = null; p2 = null; }
public override void ApplyEffect(GameContext context, Actor executor, Pos2D pos) { var targets = context.Level.GetCellsInSquare(pos, 1).Where(c => executor.CanSee(c.Pos)).ToList(); targets = targets.OrderBy(o => context.Randomizer.GetDouble()).ToList(); // This shouldn't happen, but in the case where zero cells are visible, just do nothing in general if (!targets.Any()) { if (executor.IsPlayer || context.CanPlayerSee(pos) || context.CanPlayerSee(executor.Pos)) { context.AddMessage($"{executor.Name} tries to use {Name} but had a targeting issue", ClientMessageType.Failure); } return; } if (executor.IsPlayer || context.CanPlayerSee(pos) || context.CanPlayerSee(executor.Pos)) { context.AddMessage($"{executor.Name} fires a {Name}", ClientMessageType.Generic); } // Pick 3 random targets that are visible around the target cell and fire projectiles at them foreach (var target in targets.Take(Math.Max(3, targets.Count))) { if (executor.IsPlayer || context.CanPlayerSee(target.Pos)) { context.AddEffect(new ProjectileEffect(executor, target.Pos)); } context.CombatManager.HandleExplosion(context, executor, target.Pos, 2, 1, DamageType.Normal); } }
private bool HandleCommandActivation(GameContext context, Actor executor, Pos2D pos) { executor.Operations -= ActivationCost; if (ActivationType == CommandActivationType.Active) { if (executor.IsPlayer) { context.AddMessage($"{Name} activated", ClientMessageType.Generic); context.AddEffect(new ActivatedEffect(executor, Name)); } OnActivated(context, executor, pos); } else { if (!IsSilent) { context.AddEffect(new TauntEffect(executor, $"{Name}!")); } ApplyEffect(context, executor, pos); } return(ActivationType == CommandActivationType.Active); }
public Player(Pos2D pos, PlayerType playerType) : base(pos) { PlayerType = playerType; HotbarCommands = new List <CommandSlot>(); StoredCommands = new List <CommandSlot>(); }
private List <RefillFlowRecord.Path> CollectFromPos(Container2D_Rectangular container, FillInfo[,] fillInfos, int fromX, int fromY) { if (!container.IsLegalPosition(fromX, fromY) || null != container.GetSlot(fromX, fromY)) { return(null); } var fi = fillInfos[fromY, fromX]; var ret = new List <RefillFlowRecord.Path>(); var selfPos = new Pos2D(fromX, fromY); var self = new RefillFlowRecord.Path(); self.dst = selfPos; ret.Add(self); foreach (var child in fi.childrenPos) { var sub = CollectFromPos(container, fillInfos, child.x, child.y); if (null == sub) { continue; } ret.AddRange(sub); } foreach (var r in ret) { r.src = selfPos; r.movements.Add(selfPos); } return(ret); }
void OnTap(TapGesture gesture) { if (IsAutoPlay) { return; } if (isPlaying) { return; } var worldPos = Camera.main.ScreenToWorldPoint(gesture.Position); worldPos.z = 0; var localPos = transform.InverseTransformPoint(worldPos); var logicPos = layout.View2Logic(new Vector2(localPos.x, localPos.y)); if (logicPos.x < 0 || logicPos.x >= env.Foreground.Width || logicPos.y < 0 || logicPos.y >= env.Foreground.Height) { return; } if (null == selection) { selection = logicPos; view.HighlightCell(selection.x, selection.y, true); } else if (logicPos != selection) { view.HighlightCell(selection.x, selection.y, false); var tmp = selection; selection = null; PlayInput(tmp, logicPos); } }
public override void ApplyEffect(GameContext context, Actor executor, Pos2D pos) { if (executor.IsPlayer || context.CanPlayerSee(executor.Pos) || context.CanPlayerSee(pos)) { context.AddMessage($"{executor.Name} cleanses an area of corruption.", ClientMessageType.Generic); context.AddEffect(new ProjectileEffect(executor, pos)); } const int strength = 1; var cells = context.Level.GetCellsInSquare(pos, 2); foreach (var cell in cells) { var isCellVisible = context.CanPlayerSee(cell.Pos); // Add the effect for the cell if (isCellVisible && cell.Corruption > 0) { context.AddEffect(new CleanseEffect(cell.Pos, strength)); } // Reduce base corruption cell.Corruption -= strength; // Also cleanse any objects on the cell foreach (var obj in cell.Objects.Where(o => o.IsCorruptable || (o.Team == Alignment.Bug || o.Team == Alignment.Virus)).ToList()) { obj.ApplyCorruptionDamage(context, executor, -strength); } } }
private void HandleTelefragged([NotNull] Actor actor, IEnumerable <Actor> telefragged, Pos2D oldPos, Pos2D newPos, int damage) { string hurtMessage; // Teleporting on top of another actor should always cause damage to that actor and swap it to your old location foreach (var target in telefragged) { hurtMessage = CombatManager.HurtObject(this, actor, target, damage, "scrambles", DamageType.Normal); if (actor.IsPlayer || target.IsPlayer || CanPlayerSee(newPos)) { AddMessage(hurtMessage, ClientMessageType.Generic); } Level.MoveObject(target, oldPos); } // If any collisions occurred, also hurt the actor who triggered it hurtMessage = CombatManager.HurtObject(this, actor, actor, damage, "scrambles", DamageType.Normal); if (actor.IsPlayer || Player.CanSee(newPos)) { AddMessage(hurtMessage, ClientMessageType.Generic); } }
private Pos2D SetFoV(int x, int y) { var pos = new Pos2D(x, y); _visible.Add(pos); return(pos); }
/// <summary> /// Builds a rectangular room of the specified dimensions. /// </summary> /// <param name="builder">The level builder.</param> /// <param name="upperLeft">The absolute position of the upper left point of the room.</param> /// <param name="size">The width and height of the room.</param> /// <returns>The unique identifier of the room.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// size - The X size of a constructed room must be greater than zero. /// or /// size - The Y size of a constructed room must be greater than zero. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException">size - The X and Y sizes of a constructed room must each be greater than zero.</exception> public Guid AddRectangularRoom(LevelBuilder builder, Pos2D upperLeft, Pos2D size) { // Validate if (size.X <= 0 || size.Y <= 0) { throw new ArgumentOutOfRangeException(nameof(size), "The X and Y sizes of a constructed room must be greater than zero."); } var roomGuid = Guid.NewGuid(); // Loop through the bounds and add the requested room for (var x = upperLeft.X; x <= upperLeft.X + size.X - 1; x++) { for (var y = upperLeft.Y; y <= upperLeft.Y + size.Y - 1; y++) { var isOnEdge = x == upperLeft.X || x == upperLeft.X + size.X - 1 || y == upperLeft.Y || y == upperLeft.Y + size.Y - 1; char terrain = isOnEdge ? '#' : '.'; var cell = builder.BuildCell(terrain, new Pos2D(x, y)); builder.AddCell(cell, roomGuid); } } return(roomGuid); }
public GameCell BuildPrefabCell(char terrain, Pos2D point, PrefabData sourcePrefab) { var mapping = sourcePrefab.Mapping?.FirstOrDefault(m => m.Char == terrain); if (mapping == null) { return(BuildCell(terrain, point)); } var cell = new GameCell { FloorType = FloorType.Normal, Pos = point }; // This makes debugging a bit easier if (terrain == '<' || terrain == '>') { cell.FloorType = FloorType.DecorativeTile; } var obj = GameObjectFactory.CreateObject(mapping.ObjId, mapping.ObjType, point); cell.AddObject(obj); return(cell); }
void OnTap(TapGesture gesture) { if (IsAutoPlay) return; if (isPlaying) return; var worldPos = Camera.main.ScreenToWorldPoint(gesture.Position); worldPos.z = 0; var localPos = transform.InverseTransformPoint(worldPos); var logicPos = layout.View2Logic(new Vector2(localPos.x, localPos.y)); if (logicPos.x < 0 || logicPos.x >= env.Foreground.Width || logicPos.y < 0 || logicPos.y >= env.Foreground.Height) { return; } if (null == selection) { selection = logicPos; view.HighlightCell(selection.x, selection.y, true); } else if (logicPos != selection) { view.HighlightCell(selection.x, selection.y, false); var tmp = selection; selection = null; PlayInput(tmp, logicPos); } }
public void TeleportActor([NotNull] Actor actor, Pos2D pos) { const int damage = 1; // Ensure that the teleport is allowed to happen - don't allow teleporting into walls var targetCell = Level.GetCell(pos); if (targetCell == null || targetCell.HasNonActorObstacle) { HandleFailedTeleport(actor, pos, damage); return; } // See who else is here before the action occurs var telefragged = Level.Actors.Where(a => a.Pos == pos).ToList(); var oldPos = actor.Pos; // Add an effect for the teleportation if (CanPlayerSee(actor.Pos) || CanPlayerSee(pos) || actor.IsPlayer) { AddTeleportEffect(actor, pos); } // Actually move the actor Level.MoveObject(actor, pos); if (telefragged.Any()) { HandleTelefragged(actor, telefragged, oldPos, pos, damage); } }
public override void ApplyEffect(GameContext context, Actor executor, Pos2D pos) { // Do nothing var targets = context.Level.GetTargetsAtPos(pos).ToList(); if (executor.IsPlayer || context.CanPlayerSee(pos)) { context.AddEffect(new ProjectileEffect(executor, pos)); } if (targets.Any()) { foreach (var target in targets) { context.CombatManager.HandleAttack(context, executor, target, "spikes", DamageType.Normal); } } else { if (executor.IsPlayer || context.CanPlayerSee(executor.Pos) || context.CanPlayerSee(pos)) { context.AddMessage($"{executor.Name} sends a spike into nothingness.", ClientMessageType.Failure); } } }
public override void ApplyEffect(GameContext context, Actor executor, Pos2D pos) { if (executor.AdjustStability(1) && (executor.IsPlayer || context.CanPlayerSee(executor.Pos))) { context.AddEffect(new StabilityRestoreEffect(executor, 1)); } }
private void UpdateCity(JsonCityMatrix jsonCity) { foreach (var jb in jsonCity.grid) { var pos = new Pos2D(jb.x, jb.y); if (!this._buildings.ContainsKey(pos)) { Building newB = Instantiate(this.BuildingPrefab).GetComponent <Building>(); newB.transform.parent = this.transform; newB.transform.localPosition = GetLocalPos(pos); newB.transform.localEulerAngles = Vector3.zero; newB.name = String.Format("Building {0}-{1}", pos.x, pos.y); this._buildings.Add(pos, newB); } Building b = this._buildings[pos]; b.State = GetBuildingType(jb.type); if (b.State == Building.View.Building) { if (!TopperOnly) { b.Height = jsonCity.objects.densities[jb.type]; } b.TopperPrefab = this.TopperPrefabs[jb.type]; } } }
public void LoadEmpty() { plane.gameObject.SetActive(false); cellRoot.DestroyAllChildren(); lineRoot.DestroyAllChildren(); p1 = null; p2 = null; }
public ISet <Pos2D> ComputeFov(Pos2D origin, decimal radius) { _visible.Clear(); ShadowCaster.ComputeFieldOfViewWithShadowCasting(origin.X, origin.Y, radius.ToInt(), IsOpaque, SetFoV); return(_visible); }
public BuildingChange(Pos2D pos, int oldId, int newId, int oldDensity, int newDensity) { Pos = pos; OldId = oldId; NewId = newId; OldDensity = oldDensity; NewDensity = newDensity; }
protected GameObjectBase CreateTurret(Pos2D pos) { var turret = GameObjectFactory.CreateActor(Actors.Turret, pos); Context.AddObject(turret); return(turret); }
public ChessMoveAbility(int x, int y, Tags[] tags_) { pos = new Pos2D(x, y); foreach (Tags s in tags_) { tags.Add(s); } }
public Wall(Pos2D pos) { symbole = "#"; isDrawn = true; hasCollision = true; position = pos; Game.gameObjList.Add(this as Gameobjekt); }
public void MoveObject([NotNull] GameObjectBase obj, Pos2D newPos) { var oldPos = obj.Pos; Level.MoveObject(obj, newPos); AddMessage(new MovedMessage(obj, oldPos, newPos)); }
public override bool Equals(object o) { if (o.GetType() == typeof(Pos2D)) { Pos2D p = (Pos2D)o; return(x == p.x && y == p.y); } return(base.Equals(o)); }
public override void ApplyEffect(GameContext context, Actor executor, Pos2D pos) { if (executor.IsPlayer || context.CanPlayerSee(executor.Pos) || context.CanPlayerSee(pos)) { context.AddMessage($"{executor.Name} teleports", ClientMessageType.Generic); } context.TeleportActor(executor, pos); }
private void HandleFailedTeleport([NotNull] Actor actor, Pos2D pos, int damage) { if (actor.IsPlayer || CanPlayerSee(pos)) { AddMessage($"{actor.Name} tries to teleport but is blocked, causing {damage} scramble damage.", ClientMessageType.Failure); } CombatManager.HurtObject(this, actor, actor, damage, "scrambles", DamageType.Normal); }
/// <summary> /// Creates a player object instance with stats from the defined <paramref name="playerType"/>. /// </summary> /// <returns>The player instance</returns> public static Player CreatePlayer(Pos2D pos, PlayerType playerType) { var player = new Player(pos, playerType); var commands = GetStartingCommandsForPlayer(playerType); InitializeCommandSlots(player, commands); return(player); }
public override void ApplyEffect(GameContext context, Actor executor, Pos2D pos) { if (executor.IsPlayer || context.CanPlayerSee(executor.Pos) || context.CanPlayerSee(context.Level.MarkedPos)) { context.AddMessage($"{executor.Name} recalls to the previously marked position", ClientMessageType.Success); } context.TeleportActor(executor, context.Level.MarkedPos); }
public List <ChessMove> GetValidMoves() { ChessBoard chessBoard = this.agent.ChessBoard; List <ChessMove> viableMoves = new List <ChessMove>(); // get Positions of 1 single step: // for each way in which they can move: foreach (ChessMoveAbility moveAbility in this.moveAbilities) { List <Pos2D> mirrorSteps = moveAbility.pos.mirrorPositions().ToList(); // special case for forwardonly: (pawns, striking and moving) y must be at least 1 if (moveAbility.hasTag(ChessMoveAbility.Tags.FORWARDONLY)) { mirrorSteps = mirrorSteps.FindAll(p => p.y >= 1); } foreach (Pos2D p in mirrorSteps) { Pos2D positionCandidate = p + this.pos; ChessBoard.OccupationType occupationType = chessBoard.CheckPosition(positionCandidate, this); bool positionIsViable = true; ChessMove.MoveType moveType = ChessMove.MoveType.MOVE; if (occupationType == ChessBoard.OccupationType.NONACCESS || occupationType == ChessBoard.OccupationType.NONACCESS || occupationType == ChessBoard.OccupationType.SAMEPARTY) { positionIsViable = false; } /* special case for wild horse eg. : */ if (moveAbility.hasTag(ChessMoveAbility.Tags.WILD) && occupationType == ChessBoard.OccupationType.SAMEPARTY) { positionIsViable = true; moveType = ChessMove.MoveType.CAPTURE; } if (moveAbility.hasTag(ChessMoveAbility.Tags.NOSTRIKE) && occupationType == ChessBoard.OccupationType.ENEMY) { positionIsViable = false; moveType = ChessMove.MoveType.CAPTURE; } if (moveAbility.hasTag(ChessMoveAbility.Tags.STRIKEONLY) && occupationType == ChessBoard.OccupationType.FREE) { positionIsViable = false; } if (positionIsViable) { viableMoves.Add(new ChessMove(this, positionCandidate, moveType)); } } } return(viableMoves); // if rider: get additional steps until limit distance is reached. // ridercode }
public void UpdatePosition(Pos2D newPos) { Source.Pos = newPos; NotifyOffsetChanged(); if (Source is Player) { _gameVm.CenterOn(newPos); } }
private void InsertCell(SlotAttribute sa, Pos2D pos) { if (null != cells[pos.y, pos.x]) { GameObject.Destroy(cells[pos.y, pos.x]); cells[pos.y, pos.x] = null; } var cell = cellProvider.Invoke(sa, layout.CellSize); cells[pos.y, pos.x] = cell; cell.transform.parent = goCellRoot.transform; cell.transform.localPosition = layout.Logic2View(pos); }
public void LoadData(RuleOperation2D_Rectangular rule) { plane.gameObject.SetActive(true); Draw(planeWidth, planeHeight, maskWidth, maskHeight); if (rule.xRelative != 0 || rule.yRelative != 0) { var offset = new Pos2D(rule.xRelative / 2, rule.yRelative / 2); p1 = new Pos2D(2 - offset.x, 2 - offset.y); p2 = new Pos2D(2 + rule.xRelative - offset.x, 2 + rule.yRelative - offset.y); Mark(p1.x, p1.y); Mark(p2.x, p2.y); } }
void PlayInput(Pos2D a, Pos2D b) { var input = new OperationInput(); input.x1 = a.x; input.y1 = a.y; input.x2 = b.x; input.y2 = b.y; if (!env.IsLegalOperation(input)) { return; } var output = env.PerformOperation(input); if (!output.IsRejected) { isPlaying = true; view.Play(input, output, ()=>{ isPlaying = false; }); } }
protected override void OnSelection (int logicX, int logicY) { if (null == p1 && null == p2) { Mark(logicX, logicY); p1 = new Pos2D(logicX, logicY); } else if (null != p1 && null == p2) { if (p1.x == logicX && p1.y == logicY) { p1 = null; Mark(logicX, logicY); } else { p2 = new Pos2D(logicX, logicY); Mark(logicX, logicY); } } else { if (p1.x == logicX && p1.y == logicY) { p1 = p2; p2 = null; Mark(logicX, logicY); return; } if (p2.x == logicX && p2.y == logicY) { p2 = null; Mark(logicX, logicY); return; } } }
// Tooth // 4__5<-------- OuterDiameter // / \ // 3/ \6<------ Pitch Diameter // ->|------|<------- Tooth Thickness (at Pitch Diameter) // ->|------|<------- Working Depth // 1__2 7__8 <--- Whole Depth; Root Radius private void DrawGearFace(float centerX, float centerY) { var outsideRadius = SpurGear.OutsideDiameter / 2 + centerX; var rootRadius = outsideRadius - SpurGear.WholeDepth; var pitchRadius = SpurGear.PitchDiameter / 2; var circularPitchAngle = (float)(RadInCyrcle / SpurGear.NumberOfTeeth); var toothThicknessAngle = ((float)(RadInCyrcle * SpurGear.ToothThickness) / (Math.PI * SpurGear.PitchDiameter)); var halfBottomLandPitch = ((circularPitchAngle - toothThicknessAngle) / 2f); var initVerticesCount = SpurGear.Vertices.Count; /*1*/ float startAngle = 0; var pos = new Pos2D(centerX, rootRadius + centerY); AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount); for (var i = 0; i < SpurGear.NumberOfTeeth; i++) { var pitchFacePos2D = new PitchFacePos2D(i); _pitchFacePos2Ds.Add(pitchFacePos2D); /*1-2 draw first half base*/ for (var angle = _segmentAngleInRad; angle < halfBottomLandPitch; angle += _segmentAngleInRad) { var pos2D = Pos(rootRadius, startAngle + angle, centerX, centerY); AddFace(pos2D.X, pos2D.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount); } /*2*/ pos = Pos(rootRadius, startAngle + halfBottomLandPitch, centerX, centerY); AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount); pitchFacePos2D.Add(AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount)); /*3 - draw tooth*/ pos = Pos(pitchRadius, startAngle + halfBottomLandPitch, centerX, centerY); pitchFacePos2D.Add(AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount)); /*4*/ var q = toothThicknessAngle / 4; pos = Pos(outsideRadius, startAngle + halfBottomLandPitch + q, centerX, centerY); pitchFacePos2D.Add(AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount)); /*5*/ pos = Pos(outsideRadius, startAngle + halfBottomLandPitch + toothThicknessAngle - q, centerX, centerY); pitchFacePos2D.Add(AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount)); /*6*/ pos = Pos(pitchRadius, startAngle + halfBottomLandPitch + toothThicknessAngle, centerX, centerY); pitchFacePos2D.Add(AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount)); /*7*/ pos = Pos(rootRadius, startAngle + halfBottomLandPitch + toothThicknessAngle, centerX, centerY); pitchFacePos2D.Add(AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount)); /*8* draw second half base*/ for (var angle = startAngle + halfBottomLandPitch + toothThicknessAngle; angle < circularPitchAngle; angle += _segmentAngleInRad) { pos = Pos(rootRadius, angle, centerX, centerY); pitchFacePos2D.Add(AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount)); } startAngle += circularPitchAngle; } /*1 draw last half base*/ for (var angle = _segmentAngleInRad; angle < halfBottomLandPitch; angle += _segmentAngleInRad) { pos = Pos(rootRadius, startAngle + angle, centerX, centerY); AddFace(pos.X, pos.Y, SpurGear.FaceWidth, SpurGear, 0, initVerticesCount); } foreach (var pitchFacePos2D in _pitchFacePos2Ds) { for (int i = 2; i < pitchFacePos2D.Vertices.Count; i++) { AddTriangleFace(SpurGear, null, SpurGear.Vertices.IndexOf(pitchFacePos2D.Vertices[i].Top) + 1, 3,2,1); AddTriangleFace(SpurGear, null, SpurGear.Vertices.IndexOf(pitchFacePos2D.Vertices[i - 1].Top) + 1, 3, 2, 1); AddTriangleFace(SpurGear, null, SpurGear.Vertices.IndexOf(pitchFacePos2D.Vertices[i - 2].Top) + 1, 3, 2, 1); } } }
private static IEnumerable<Pos2D> GetPositionsForGear(float radius, float centerX, float centerY, int segmentAngle) { var startPosition = new Pos2D(0 + centerX, radius + centerY); yield return startPosition; for (var angle = segmentAngle; angle < 360 + segmentAngle; angle += segmentAngle) { var rad = angle*Rad2DegRatio; yield return new Pos2D((float) (radius*Math.Sin(rad)) + centerX, (float) (radius*Math.Cos(rad)) + centerY); } yield return startPosition; }
public Vector2 Logic2View(Pos2D pos) { return new Vector2(startX + cellHalfWidth + pos.x * cellWidth, startY + cellHalfHeight + pos.y * cellHeight); }
private List<RefillFlowRecord.Path> CollectFromPos(Container2D_Rectangular container, FillInfo[,] fillInfos, int fromX, int fromY) { if (!container.IsLegalPosition(fromX, fromY) || null != container.GetSlot(fromX, fromY)) return null; var fi = fillInfos[fromY, fromX]; var ret = new List<RefillFlowRecord.Path>(); var selfPos = new Pos2D(fromX, fromY); var self = new RefillFlowRecord.Path(); self.dst = selfPos; ret.Add(self); foreach (var child in fi.childrenPos) { var sub = CollectFromPos(container, fillInfos, child.x, child.y); if (null == sub) continue; ret.AddRange(sub); } foreach (var r in ret) { r.src = selfPos; r.movements.Add(selfPos); } return ret; }