Ejemplo n.º 1
0
        public MapTile[] GeneratePath(Point start, Point end, Map map)
        {
            List <MapTile> path = new List <MapTile>();
            //DEBUG
            int counter = 0;

            Point active = start;

            path.Add(map.map.Get(active));

            while (active != end)
            {
                //DEBUG
                if (++counter == 100)
                {
                    throw new Exception("Something went wrong!");
                }

                //Find field with lowest value for graph (lowest movement cost from start)
                List <Point> fields = AIUtility.GetFields(active, this);
                active = fields.Aggregate((best, field) => {
                    if (path.Exists(f => f.position == field))
                    {
                        return(best);
                    }
                    double b = graph[best.X, best.Y]; //Do not use Get method for optimization
                    double n = graph[field.X, field.Y];
                    if (n == b)
                    {
                        int bestDistance  = AIUtility.Distance(best, end);
                        int fieldDistance = AIUtility.Distance(field, end);
                        //if they have the same cost take the one which is closer if they are the same distance take the newer
                        return(bestDistance >= fieldDistance ? field : best);
                    }
                    else
                    {
                        if (b > n)
                        {
                            return(field);
                        }
                        else
                        {
                            return(best);
                        }
                    }
                });

                path.Add(map.map.Get(active));
            }
            return(path.ToArray());
        }
Ejemplo n.º 2
0
        public override void PlayTurn(MainGameWindow main, bool singleTurn)
        {
            //Decrease spell cooldown
            foreach (Spell spell in spells)
            {
                spell.coolDown = spell.coolDown == 0 ? 0 : spell.coolDown - 1;
            }

            //Panic if he has been hit or player is close and he is on low health
            if (troop.health.Value != lastHealth || (AIUtility.Distance(troop.Position, enemies[0].troop.Position) < 4 && troop.health.Value != troop.health.MaxValue().Value))
            {
                lastHealth = troop.health.Value;
                //If teleport spell is ready
                if (spells[1].Ready)
                {
                    //Find heighest free space
                    var HeightSorted = from field in map.map.Cast <MapTile>()
                                       where field.free
                                       where AIUtility.Distance(field.position, enemies[0].troop.Position) > 10
                                       orderby field.Height descending
                                       select field;
                    //Teleport
                    spells[1].Activate(new SpellInformation()
                    {
                        positions = new List <Point>()
                        {
                            troop.Position, HeightSorted.Take(1).ToList()[0].position
                        }, mage = this
                    });
                    return; //Finish turn
                }
                else
                {
                    main.WriteConsole("The wizard wimpers");
                    return;
                }
            }

            //Attack
            if (spells[0].Ready)
            {
                spells[0].Activate(new SpellInformation()
                {
                    positions = new List <Point> {
                        enemies[0].troop.Position
                    }, mage = this
                });
            }
        }
Ejemplo n.º 3
0
        public override void PlayTurn(MainGameWindow main, bool SingleTurn)
        {
            DistanceGraphCreator distanceGraph = new DistanceGraphCreator(this, troop.Position.X, troop.Position.Y, map, false);
            Thread path = new Thread(distanceGraph.CreateGraph);

            path.Start();
            path.Join();

            int damageDealt = 0;
            int dodged      = 0;

            while (actionPoints.Value > 0)
            {
                Point playerPos = enemies[0].troop.Position;

                //Check if it can attack player
                int playerDistance = AIUtility.Distance(playerPos, troop.Position);
                if (playerDistance <= troop.activeWeapon.range &&
                    troop.activeWeapon.Attacks() > 0)
                {
                    //Attack
                    var(damage, killed, hit) = main.Attack(this, enemies[0]);
                    damageDealt += damage;
                    if (!hit)
                    {
                        dodged++;
                    }

                    if (killed)
                    {
                        map.overlayObjects.Add(new OverlayText(enemies[0].troop.Position.X * MapCreator.fieldSize, enemies[0].troop.Position.Y * MapCreator.fieldSize, Color.Red, $"-{damageDealt}"));
                        main.PlayerDied($"You have been killed by {Name}!");
                        break;
                    }
                    actionPoints.RawValue--;
                    troop.activeWeapon.UseWeapon(enemies[0], main);
                    main.RenderMap();
                    continue;
                }
                else if (troop.weapons.Exists(t => t.range >= playerDistance && t.Attacks() > 0))
                {
                    //Change weapon
                    Weapon best = troop.weapons.FindAll(t => t.range >= playerDistance)
                                  .Aggregate((t1, t2) => t1.range > t2.range ? t1 : t2);
                    troop.activeWeapon = best;
                    continue;
                }

                Point closestField = new Point(-1, -1);
                try
                {
                    // Try finding closer field to player
                    closestField = AIUtility.FindClosestField(distanceGraph, playerPos, movementPoints.Value, map,
                                                              (List <(Point point, double cost, double height)> list) => {
                        list.Sort((o1, o2) => {
                            double diffCost   = o1.cost - o2.cost;
                            double heightDiff = o1.height - o2.height;
                            if (Math.Abs(diffCost) >= 1)     //assume that using the weapon costs 1 action point
                            {
                                return(diffCost < 0 ? -1 : 1);
                            }
                            else if (heightDiff != 0)
                            {
                                return(diffCost < 0 ? -1 : 1);
                            }
                            return(0);
                        });
                        return(list.First().point);
                    });
                }
Ejemplo n.º 4
0
        public override void PlayTurn(MainGameWindow main, bool SingleTurn)
        {
            DistanceGraphCreator distanceGraph = new DistanceGraphCreator(this, troop.Position, map, true);
            Thread path = new Thread(distanceGraph.CreateGraph);
            DistanceGraphCreator eggGraph = new DistanceGraphCreator(this, troop.Position, map, true);
            Thread pathE = new Thread(eggGraph.CreateGraph);

            path.Start();
            pathE.Start();

            int damageDealt = 0;
            int dodged      = 0;

            Point player = enemies[0].troop.Position;

            int playerDistance = AIUtility.Distance(player, troop.Position);

            if (!enraged && AIUtility.Distance(troop.Position, player) < 30 && AIUtility.Distance(egg, player) < 20)
            {
                enraged = true;
                main.WriteConsole($"{Name} has become enraged!");
                main.Combat -= Update;
            }

            void AttackPlayer(bool continues = false)
            {
                bool attacked = false;

                //Check if it can attack player
                foreach (var weapon in troop.weapons)
                {
                    if (playerDistance <= weapon.range &&
                        weapon.Attacks() > 0)
                    {
                        //Attack
                        troop.activeWeapon       = weapon;
                        var(damage, killed, hit) = main.Attack(this, enemies[0]);
                        damageDealt += damage;
                        if (!hit)
                        {
                            dodged++;
                        }

                        if (killed)
                        {
                            map.overlayObjects.Add(new OverlayText(enemies[0].troop.Position.X * MapCreator.fieldSize, enemies[0].troop.Position.Y * MapCreator.fieldSize, Color.Red, $"-{damageDealt}"));
                            main.PlayerDied($"You have been killed by {Name} using {weapon.name}!");
                        }
                        actionPoints.RawValue--;
                        weapon.UseWeapon(enemies[0], main);
                        attacked = true;
                    }
                }
                if (attacked)
                {
                    AttackPlayer(true);
                }
            }

            if (enraged)
            {
                if (fireLineCoolDown == 0 && playerDistance > 5)
                {
                    //Spew fire

                    //Shoot fire line - will most likely not kill but be in the area
                    Point end = new Point(player.X + (World.World.random.Next(0, 2) == 1 ? -2 : 2), player.Y + (World.World.random.Next(0, 2) == 1 ? -2 : 2));

                    Point diff  = end.Sub(troop.Position);
                    Point start = troop.Position.Add(diff.Div(5));

                    int diffX = diff.X;
                    int diffY = diff.Y;
                    int time  = Math.Max(Math.Abs(diffX), Math.Abs(diffY));
                    main.actionOccuring = true;
                    lock (map.RenderController)
                    {
                        for (int i = 0; i < time; i++)
                        {
                            Point position = new Point(Math.Max(start.X + (int)(((double)diffX / time) * i), 0), Math.Max(start.Y + (int)(((double)diffY / time) * i), 0));
                            new Fire(World.World.random.Next(5) + 2, 5, position, troop.Position, map, main);
                        }
                    }
                    main.actionOccuring = false;
                    fireLineCoolDown    = maxFireLineCooldown;
                }
                else
                {
                    fireLineCoolDown = fireLineCoolDown == 0 ? 0 : fireLineCoolDown - 1;
                }

                if (fireBombPlaces.Count != 0)
                {
                    lock (map.RenderController)
                    {
                        main.actionOccuring = true;
                        int appliedRadius = 2;
                        //Fire real explosions
                        foreach (var hit in fireBombPlaces)
                        {
                            for (int x = 0; x < appliedRadius * 2 + 1; x++)
                            {
                                for (int y = 0; y < appliedRadius * 2 + 1; y++)
                                {
                                    //Check in bounds
                                    Point point = new Point(x + hit.X - appliedRadius, y + hit.Y - appliedRadius);
                                    if ((point.X < 0 || point.X >= map.map.GetUpperBound(0) - 1) || (point.Y < 0 || point.Y >= map.map.GetUpperBound(1) - 1))
                                    {
                                        continue;
                                    }

                                    int dis = AIUtility.Distance(point, hit);
                                    if (dis <= appliedRadius)
                                    {
                                        //Damage fields
                                        new Fire(World.World.random.Next(0, 6), fireDamage, point, point, map, main);
                                    }
                                }
                            }
                        }
                        main.actionOccuring = false;
                    }
                    fireBombPlaces.Clear();
                }

                if (fireBombCoolDown == 0)
                {
                    //Summon fire explosions at certain positions - first one then ring

                    int tries = 0; //Longerm: Create deterministic version
                    while (tries != 100 && fireBombPlaces.Count < bombNumber)
                    {
                        Point test = new Point(World.World.random.Next(0, map.map.GetUpperBound(0)), World.World.random.Next(map.map.GetUpperBound(1)));
                        if (AIUtility.Distance(test, player) < 20 && AIUtility.Distance(test, troop.Position) > 3)
                        {
                            fireBombPlaces.Add(test);
                        }
                        tries++;
                    }

                    if (tries == 100)
                    {
                        E.LogInfo("Did not find locations for fire bombs!");
                    }
                    else
                    {
                        bombNumber++;
                    }

                    lock (map.RenderController)
                    {
                        foreach (var point in fireBombPlaces)
                        {
                            new Fire(World.World.random.Next(3, 8), fireDamage, point, troop.Position, map, main);
                        }
                    }
                    fireBombCoolDown = maxFireBombCooldown;
                }
                else
                {
                    fireBombCoolDown--;
                }

                AttackPlayer();
            }

            //Find field to move to
            //If enraged go to player
            //If player is close to camp go to player
            //Else stay around camp
            if (actionPoints.Value == 0)
            {
                path.Abort();
                pathE.Abort();
                return;
            }

            Point closestField;

            path.Join();
            pathE.Join();

            DistanceGraphCreator graph = enraged || AIUtility.Distance(egg, player) < 8 ? distanceGraph : eggGraph;
            Point goalPos = enraged || AIUtility.Distance(egg, player) < 8 ? player : egg;

            if (jumpCooldown == 0 && enraged)
            {
                //Jump towards player and create earthquake
                closestField = AIUtility.FindClosestField(graph, goalPos, jumpDistance, map,
                                                          (List <(Point point, double cost, double height)> list) => {
                    list.Sort((o1, o2) => {
                        double diffCost   = o1.cost - o2.cost;
                        double heightDiff = o1.height - o2.height;
                        if (Math.Abs(diffCost) >= 1) //assume that using the weapon costs 1 action point
                        {
                            return(diffCost < 0 ? -1 : 1);
                        }
                        else if (heightDiff != 0)
                        {
                            return(diffCost < 0 ? -1 : 1);
                        }
                        return(0);
                    });
                    return(list.First().point);
                });
Ejemplo n.º 5
0
        public static void GeneralFighterAI(MainGameWindow main, bool SingleTurn, Player ai, Map map)
        {
            //TODO: Seperate code, which logs details from code which decides what to do
            Troop                troop          = ai.troop;
            var                  enemies        = ai.enemies;
            ActionPoint          actionPoints   = ai.actionPoints;
            MovementPoints       movementPoints = ai.movementPoints;
            DistanceGraphCreator distanceGraph  = new DistanceGraphCreator(ai, troop.Position.X, troop.Position.Y, map, true);
            Thread               path           = new Thread(distanceGraph.CreateGraph);

            path.Start();
            path.Join();

            int damageDealt = 0;
            int dodged      = 0;

            while (actionPoints.Value > 0)
            {
                Point playerPos = enemies[0].troop.Position;

                //If the weapon is ranged and empty first load the weapon
                if (troop.activeWeapon.Attacks() == 0 && troop.activeWeapon is RangedWeapon w)
                {
                    Ammo selectedAmmo = w.GetSelectedAmmo();
                    foreach (var ammo in w.Ammo)
                    {
                        if (selectedAmmo is null || selectedAmmo.damage.Value < ammo.damage.Value)
                        {
                            ammo.Select(w);
                            selectedAmmo = ammo;
                        }
                    }
                }

                //Check if it can attack player
                int playerDistance = AIUtility.Distance(playerPos, troop.Position);
                int attacks        = troop.activeWeapon.Attacks();
                if (playerDistance <= troop.activeWeapon.range && attacks > 0)
                {
                    //Attack
                    var(damage, killed, hit) = main.Attack(ai, enemies[0]);
                    damageDealt += damage;
                    if (!hit)
                    {
                        dodged++;
                    }

                    if (killed)
                    {
                        map.overlayObjects.Add(new OverlayText(enemies[0].troop.Position.X * MapCreator.fieldSize, enemies[0].troop.Position.Y * MapCreator.fieldSize, Color.Red, $"-{damageDealt}"));
                        main.PlayerDied($"You have been killed by {ai.Name}!");
                        break;
                    }
                    actionPoints.RawValue--;
                    troop.activeWeapon.UseWeapon(enemies[0], main);
                    continue;
                }
                else if (troop.weapons.Exists(t => t.range >= playerDistance && t.Attacks() > 0))
                {
                    //Change weapon
                    Weapon best = troop.weapons.FindAll(t => t.range >= playerDistance)
                                  .Aggregate((t1, t2) => t1.range > t2.range ? t1 : t2);
                    troop.activeWeapon = best;
                    continue;
                }

                //Generate map of left value
                double[,] movementCosts = new double[map.width, map.height];
                for (int x = 0; x <= movementCosts.GetUpperBound(0); x++)
                {
                    for (int y = 0; y <= movementCosts.GetUpperBound(1); y++)
                    {
                        movementCosts[x, y] = -1;
                    }
                }

                //Find closest field to player
                Point closestField = new Point(-1, -1);
                try
                {
                    closestField = AIUtility.FindClosestField(distanceGraph, playerPos, movementPoints.Value, map,
                                                              (List <(Point point, double cost, double height)> list) => {
                        list.Sort((o1, o2) => {
                            double diffCost   = o1.cost - o2.cost;
                            double heightDiff = o1.height - o2.height;
                            if (Math.Abs(diffCost) >= 1)     //assume that using the weapon costs 1 action point
                            {
                                return(diffCost < 0 ? -1 : 1);
                            }
                            else if (heightDiff != 0)
                            {
                                return(diffCost < 0 ? -1 : 1);
                            }
                            return(0);
                        });
                        return(list.First().point);
                    });
                }