public bool CanMoveTo(int relX, int relY) { // TODO only referenced by land units, move to BaseUnitLand? // Issue #93: fix problems with zone-of-control. // refactored out for unit testability ITile moveTarget = Map[X, Y][relX, relY]; if (moveTarget == null) { return(false); } // Issue #116: allow ship-borne units to move to any unoccupied tile if (Map[X, Y].IsOcean) { return(!moveTarget.Units.Any(u => u.Owner != Owner)); } var thisUnits = Map[X, Y].GetBorderTiles().SelectMany(t => t.Units); var destUnits = moveTarget.GetBorderTiles().SelectMany(t => t.Units); // Any enemy units around my position OR the target position? bool thisBlocked = thisUnits.Any(u => u.Owner != Owner); bool destBlocked = destUnits.Any(u => u.Owner != Owner); bool destOK = moveTarget.Units.Any(u => u.Owner == Owner) || moveTarget.HasCity; // Cannot move from a square adjacent to enemy unit to a square adjacent to enemy unit // but _can_ move to square occupied by own units or to any undefended city square return(destOK || !thisBlocked || !destBlocked); }
public bool BuildIrrigation() { ITile tile = Map[X, Y]; if (tile.Irrigation) { // Tile already irrigated, ignore return(false); } if ((tile is Forest) || (tile is Jungle) || (tile is Swamp)) { BuildingIrrigation = 4; MovesLeft = 0; PartMoves = 0; return(true); } else if ((tile.GetBorderTiles().Any(t => (t.X == X || t.Y == Y) && (t.City == null) && (t.IsOcean || t.Irrigation || (t is River)))) || (tile is River)) { if (!tile.IsOcean && !(tile.Irrigation) && ((tile is Desert) || (tile is Grassland) || (tile is Hills) || (tile is Plains) || (tile is River))) { BuildingIrrigation = 3; MovesLeft = 0; PartMoves = 0; return(true); } if (Human == Owner) { GameTask.Enqueue(Message.Error("-- Civilization Note --", TextFile.Instance.GetGameText("ERROR/NOIRR"))); } return(false); } else { if (((tile is Desert) || (tile is Grassland) || (tile is Hills) || (tile is Plains) || (tile is River)) && tile.City == null) { if (Human == Owner) { GameTask.Enqueue(Message.Error("-- Civilization Note --", TextFile.Instance.GetGameText("ERROR/NOWATER"))); } return(true); } if (Human == Owner) { GameTask.Enqueue(Message.Error("-- Civilization Note --", TextFile.Instance.GetGameText("ERROR/NOIRR"))); } } return(false); }
public virtual bool MoveTo(int relX, int relY) { if (Movement != null) { return(false); } ITile moveTarget = Map[X, Y][relX, relY]; if (moveTarget == null) { return(false); } if (moveTarget.Units.Any(u => u.Owner != Owner)) { if (Class == UnitClass.Land && Tile.IsOcean) { GameTask.Enqueue(Message.Error("-- Civilization Note --", TextFile.Instance.GetGameText($"ERROR/AMPHIB"))); return(false); } return(Confront(relX, relY)); } if (Class == UnitClass.Land && !(this is Diplomat || this is Caravan) && !new ITile[] { Map[X, Y], moveTarget }.Any(t => t.IsOcean || t.City != null) && moveTarget.GetBorderTiles().SelectMany(t => t.Units).Any(u => u.Owner != Owner)) { if (!moveTarget.Units.Any(x => x.Owner == Owner)) { IUnit[] targetUnits = moveTarget.GetBorderTiles().SelectMany(t => t.Units).Where(u => u.Owner != Owner).ToArray(); IUnit[] borderUnits = Map[X, Y].GetBorderTiles().SelectMany(t => t.Units).Where(u => u.Owner != Owner).ToArray(); if (borderUnits.Any(u => targetUnits.Any(t => t.X == u.X && t.Y == u.Y))) { if (Human == Owner) { GameTask.Enqueue(Message.Error("-- Civilization Note --", TextFile.Instance.GetGameText($"ERROR/ZOC"))); } return(false); } } } if (moveTarget.City != null && Map[X, Y][relX, relY].City.Owner != Owner) { return(Confront(relX, relY)); } if (!MoveTargets.Any(t => t.X == moveTarget.X && t.Y == moveTarget.Y)) { // Target tile is invalid // TODO: For some tiles, display a message detailing why the move is illegal return(false); } // TODO: This implementation was done by observation, may need a revision if (MovesLeft == 0 && !moveTarget.Road && moveTarget.Movement > 1) { bool success; if (PartMoves >= 2) { // 2/3 moves left? 50% chance of success success = (Common.Random.Next(0, 2) == 0); } else { // 2/3 moves left? 33% chance of success success = (Common.Random.Next(0, 3) == 0); } if (!success) { PartMoves = 0; return(false); } } Movement = new MoveUnit(relX, relY); Movement.Done += MoveEnd; GameTask.Insert(Movement); return(true); }