/* Update the interface_t object with the information returned * in get_map_cursor_type(). This is sets the appropriate values * when the player interface is in road construction mode. */ void DetermineMapCursorTypeRoad() { var map = Game.Map; var position = mapCursorPosition; int height = (int)map.GetHeight(position); int validDirection = 0; var cycle = DirectionCycleCW.CreateDefault(); foreach (var direction in cycle) { uint sprite = 0; if (buildingRoad.IsUndo(direction)) { sprite = 44; // undo validDirection |= Misc.Bit((int)direction); } else if (map.IsRoadSegmentValid(position, direction, true)) { if (buildingRoad.IsValidExtension(map, direction)) { int heightDifference = (int)map.GetHeight(map.Move(position, direction)) - height; sprite = (uint)(38 + heightDifference); // height indicators validDirection |= Misc.Bit((int)direction); } else { sprite = 43; } } else { sprite = 43; // striped } mapCursorSprites[(int)direction + 1].Sprite = sprite; } buildingRoadValidDir = validDirection; }
void DrawMapCursor() { if (ShowPossibleBuilds) { DrawMapCursorPossibleBuild(); } else { ClearMapCursorPossibleBuild(); } var position = interf.GetMapCursorPosition(); DrawMapCursorSprite(position, 0, interf.GetMapCursorSprite(0)); var cycle = DirectionCycleCW.CreateDefault(); foreach (var direction in cycle) { DrawMapCursorSprite(map.Move(position, direction), 1 + (int)direction, interf.GetMapCursorSprite(1 + (int)direction)); } }
public override void Update(AI ai, Game game, Player player, PlayerInfo playerInfo, int tick) { lock (linkingLock) { if (linkingCount > 0) { return; } } var flags = game.GetPlayerFlags(player); // check if memorized flags still exist // otherwise remove them var keys = connectTriesPerFlag.Keys.ToList(); foreach (var key in keys) { try { if (game.GetFlag(key.Index) == null) { connectTriesPerFlag.Remove(key); } } catch (KeyNotFoundException) { connectTriesPerFlag.Remove(key); } } lock (linkingFailedLock) { keys = linkingFailed.Keys.ToList(); foreach (var key in keys) { try { if (game.GetFlag(key.Index) == null) { linkingFailed.Remove(key); } } catch (KeyNotFoundException) { linkingFailed.Remove(key); } } } try { foreach (var flag in flags) { // If it failed to link a flag we will only re-check it // after 2 minutes. lock (linkingFailedLock) { if (linkingFailed.ContainsKey(flag)) { int time = linkingFailed[flag]; if (tick < time) { time = int.MaxValue - time + tick; } else { time = tick - time; } if (time >= 2 * Global.TICKS_PER_MIN) { linkingFailed.Remove(flag); } else { continue; } } } if (!connectTriesPerFlag.ContainsKey(flag)) { connectTriesPerFlag[flag] = 0; } if ((flag.LandPaths == 0 || flag.FindNearestInventoryForSerf() == -1) && ++connectTriesPerFlag[flag] < 3) { LinkFlag(ai, flag, 9, false, tick); return; } } foreach (var flag in flags) { bool finishedLinking = false; if (flag.HasBuilding) { var building = flag.Building; // don't link flags of foresters and farms more than necessary as they need space for their work if (building.BuildingType == Building.Type.Forester || building.BuildingType == Building.Type.Farm) { finishedLinking = true; } } // TODO: maybe check later if there are foresters or farms around and stop linking in the area then // we also check if the link is good if (!finishedLinking) { var cycle = DirectionCycleCW.CreateDefault(); var paths = new List <Direction>(); foreach (var direction in cycle) { if (flag.HasPath(direction)) { paths.Add(direction); } } if (paths.Count < 6) { int shortestPath = int.MaxValue; foreach (var direction in paths) { int pathLength = (int)flag.GetRoad(direction).Length; if (pathLength < shortestPath) { shortestPath = pathLength; } if (shortestPath == 2) { break; } } if (shortestPath > 2 + paths.Count * 2) { LinkFlag(ai, flag, 2 + paths.Count * 2, true, tick); return; } else { var nearbyFlags = game.Map.FindInArea(flag.Position, 4, FindFlag, 2); if (nearbyFlags.Count > paths.Count) { LinkFlag(ai, game, flag, nearbyFlags, 4, true, tick); return; } } } } } } finally { lock (linkingLock) { if (linkingCount < 0) { linkingCount = 0; } } Kill(ai); } }
int CheckCastleSpot(AI ai, Game game, Player player, MapPos position, int intelligence) { var map = game.Map; int treeCount = map.FindInArea(position, 5, FindTree, 1).Count; int stoneCount = map.FindInArea(position, 5, FindStone, 1).Count; int fishCount = map.FindInArea(position, 7, FindFish, 1).Count; int mountainCountNear = map.FindInArea(position, 4, FindMountain, 0).Count; int mountainCountFar = map.FindInArea(position, 9, FindMountain, 4).Count; int desertCount = map.FindInArea(position, 6, FindDesert, 0).Count; int waterCount = map.FindInArea(position, 6, FindWater, 0).Count; int numLargeSpots = 3; int numSmallSpots = 3; int keepDistanceToEnemies = 30 - (aggressivity / 2) * 10; if (player.InitialSupplies < 5) { // we need coal and iron close enough when starting with low supplies var minerals = map.FindInArea(position, 9, FindMineral, 1).Select(m => (KeyValuePair <Map.Minerals, uint>)m); int ironCount = minerals.Where(m => m.Key == Map.Minerals.Iron).Select(m => (int)m.Value).Sum(); int coalCount = minerals.Where(m => m.Key == Map.Minerals.Coal).Select(m => (int)m.Value).Sum(); if (ironCount == 0 || coalCount == 0) { return(-1); } } else // good amount of starting resources { if (map.Size > 5) { if (treeCount < 12 || stoneCount < 6) { return(-1); } } else if (map.Size == 5) { if (treeCount < 9 || stoneCount < 5) { return(-1); } } else if (map.Size == 4) { if (treeCount < 7 || stoneCount < 4) { return(-1); } } } // if we tried too often we will only assure that there is a bit of trees and stones if (numTries >= 25 + map.Size * 5) { if (treeCount < 5 || stoneCount < 2) { return(-1); } if (numTries < 500) // after 500 tries, just place it somewhere { if (mountainCountNear > 7) // too close to mountain { return(-1); } if (desertCount > 6) // too much desert { return(-1); } if (waterCount > 8) // too much water { return(-1); } if (player.InitialSupplies < 3) // with 3 or more we have 1 iron ore and 1 coal { if (fishCount == 0 || stoneCount < 2 || treeCount < 5) { return(-1); } } numLargeSpots = 2; // the toolmaker can be build when we have expanded the land if (numTries >= 80 && player.InitialSupplies > 4) { numLargeSpots = 1; // we need to expand the territory to build the sawmill } if (game.Map.Size < 5) { // in small maps we no longer force enemy distance after many tries if (numTries >= 120) { keepDistanceToEnemies = 0; } else if (numTries >= 80) { keepDistanceToEnemies = 15; } } else if (numTries >= 200) // if tried very long we will have mercy in any case { keepDistanceToEnemies = 0; } } } else { if (mountainCountNear > 4) // too close to mountain { return(-1); } if (desertCount > 3) // too much desert { return(-1); } if (desertCount + waterCount + mountainCountNear + mountainCountFar > 10) // too much desert/water/mountain { return(-1); } var minerals = map.FindInArea(position, 9, FindMineral, 1).Select(m => (KeyValuePair <Map.Minerals, uint>)m); int stoneOreCount = minerals.Where(m => m.Key == Map.Minerals.Stone).Select(m => (int)m.Value).Sum(); int goldCount = minerals.Where(m => m.Key == Map.Minerals.Gold).Select(m => (int)m.Value).Sum(); int ironCount = minerals.Where(m => m.Key == Map.Minerals.Iron).Select(m => (int)m.Value).Sum(); int coalCount = minerals.Where(m => m.Key == Map.Minerals.Coal).Select(m => (int)m.Value).Sum(); if (player.InitialSupplies < 5) { if (treeCount < 8 || stoneCount < 4 || fishCount < 1 || ironCount == 0 || coalCount == 0) { return(-1); } } // low intelligence will treat half the mountains as the right mineral without checking int halfMountainCount = (mountainCountNear + mountainCountFar) / 2; int minConstructionCount = 3 + intelligence / 10 + Math.Max(buildingFocus, constructionMaterialFocus) * 5; if (treeCount + stoneCount + Math.Max(halfMountainCount, stoneOreCount) < minConstructionCount) { return(-1); } int minFishCount = foodFocus * 5 + (player.InitialSupplies < 5 ? 1 : 0); if (fishCount < minFishCount) { return(-1); } int minSteelCount = Math.Max(steelFocus, militaryFocus / 2) * 2; int steelOreCount = (intelligence < 20) ? Math.Max(halfMountainCount, ironCount + coalCount) : ironCount + coalCount; if (steelOreCount < minSteelCount) { return(-1); } int minGoldCount = goldFocus / 2; int goldOreCount = (intelligence < 20) ? Math.Max(halfMountainCount, goldCount) : ironCount + coalCount; if (goldCount < minGoldCount) { return(-1); } } if (keepDistanceToEnemies > 0 && numTries < 1000) { for (uint i = 0; i < game.PlayerCount; ++i) { var enemy = game.GetPlayer(i); if (enemy == player || !enemy.HasCastle) { continue; } int distance = Math.Min(Math.Abs(game.Map.DistanceX(position, enemy.CastlePosition)), Math.Abs(game.Map.DistanceY(position, enemy.CastlePosition))); if (distance < keepDistanceToEnemies) { return(-1); } } } // check if we can build at least: lumberjack, stonecutter, sawmill, toolmaker and one hut // -> 3 small and 2 large buildings // but we check the castle too, so 3 large buildings int numSmall = 0; int numLarge = 0; List <uint> largeSpots = new List <uint>(); // If the AI is smart we better use a spot with more large spots. if (numTries < 25 + map.Size * 5) { numLargeSpots += ai.Smartness; } for (int i = 0; i < 100; ++i) { uint checkPosition = map.PositionAddSpirally(position, (uint)i); if (game.CanBuildLarge(checkPosition)) { ++numSmall; ++numLarge; largeSpots.Add(checkPosition); } else if (game.CanBuildSmall(checkPosition)) { ++numSmall; } if (numLarge >= numLargeSpots && (numSmall - numLargeSpots) >= numSmallSpots) { if (ai.Smartness == 0) { return((int)largeSpots[0]); } else { foreach (var spot in largeSpots) { var flagPosition = map.MoveDownRight(spot); var directions = new DirectionCycleCW(Direction.Up, 5); bool obstacleFound = false; foreach (var direction in directions) { if (Map.MapSpaceFromObject[(int)map.GetObject(map.Move(flagPosition, direction))] >= Map.Space.Semipassable) { obstacleFound = true; break; } } if (!obstacleFound) { return((int)spot); } } } } } return(-1); }