Example #1
0
        /* 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;
        }
Example #2
0
        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));
            }
        }
Example #3
0
        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);
        }