Exemplo n.º 1
0
        /// <summary>
        /// Returns the points in a triangular target (i.e. shotgun weapon) from origin to target.
        /// Only returns points within FOV. Moral: If you can see it, you can shoot it.
        /// fovAngle = spread of target
        /// </summary>
        /// <param name="location"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public List <Point> GetPointsForTriangularTargetInFOV(Point origin, Point target, Map mapLevel, int range, double fovAngle)
        {
            if (origin == target)
            {
                return(new List <Point>());
            }

            List <Point> triangularPoints = new List <Point>();

            double angle = DirectionUtil.AngleFromOriginToTarget(origin, target);

            for (int i = origin.x - range; i < origin.x + range; i++)
            {
                for (int j = origin.y - range; j < origin.y + range; j++)
                {
                    if (new Point(i, j) == origin)
                    {
                        continue;
                    }

                    //Check for creature's FOV
                    //If OK, check to see if it falls within a TriangularFOV (blast radius)
                    if (i >= 0 && i < mapLevel.width && j >= 0 && j < mapLevel.height)
                    {
                        if (CheckTileFOV(i, j) && CreatureFOV.TriangularFOV(origin, angle, range, i, j, fovAngle))
                        {
                            triangularPoints.Add(new Point(i, j));
                        }
                    }
                }
            }

            return(triangularPoints);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Override the following code from the simple throwing AI to include backing away
        /// </summary>
        /// <param name="newTarget"></param>
        protected override void FollowAndAttack(Creature newTarget)
        {
            double range = Utility.GetDistanceBetween(this, newTarget);

            CreatureFOV currentFOV = Game.Dungeon.CalculateCreatureFOV(this);
            CreatureFOV playerFOV  = Game.Dungeon.CalculateCreatureFOV(Game.Dungeon.Player);

            bool backAwayFromTarget = false;

            //Back away if we are too close & can see the target
            //If we can't see the target, don't back away
            if (range < GetMissileRange() / 2.0 && currentFOV.CheckTileFOV(newTarget.LocationMap.x, newTarget.LocationMap.y))
            {
                //Enforce a symmetry FOV
                if (newTarget != Game.Dungeon.Player ||
                    (newTarget == Game.Dungeon.Player && playerFOV.CheckTileFOV(this.LocationMap)))
                {
                    //Check our chance to back away. For a hard/clever creature this is 100. For a stupid creature it is 0.
                    if (Game.Random.Next(100) < GetChanceToBackAway())
                    {
                        backAwayFromTarget = true;
                    }
                }
            }

            if (backAwayFromTarget && CanMove() && WillPursue())
            {
                //Target is too close, so back away before firing

                int deltaX = newTarget.LocationMap.x - this.LocationMap.x;
                int deltaY = newTarget.LocationMap.y - this.LocationMap.y;

                //Find a point in the dungeon to flee to
                int fleeX = 0;
                int fleeY = 0;

                int counter = 0;

                bool relaxDirection = false;
                bool goodPath       = false;

                Point nextStep = new Point(0, 0);

                int totalFleeLoops   = GetTotalFleeLoops();
                int relaxDirectionAt = RelaxDirectionAt();

                do
                {
                    //This performs badly when there are few escape options and you are close to the edge of the map
                    fleeX = Game.Random.Next(Game.Dungeon.Levels[this.LocationLevel].width);
                    fleeY = Game.Random.Next(Game.Dungeon.Levels[this.LocationLevel].height);

                    //Relax conditions if we are having a hard time
                    if (counter > relaxDirectionAt)
                    {
                        relaxDirection = true;
                    }

                    //Find the square to move to
                    Pathing.PathingPermission permission = Pathing.PathingPermission.Normal;
                    if (CanOpenDoors())
                    {
                        permission = Pathing.PathingPermission.IgnoreDoors;
                    }

                    nextStep = Game.Dungeon.Pathing.GetPathToPoint(this.LocationLevel, this.LocationMap, new Point(fleeX, fleeY), PathingType(), permission).MonsterFinalLocation;

                    //Check the square is pathable to
                    if (nextStep.x == LocationMap.x && nextStep.y == LocationMap.y)
                    {
                        counter++;
                        //LogFile.Log.LogEntryDebug("MonsterThrowAndRunAI: Back away fail unpathable", LogDebugLevel.Low);
                        continue;
                    }

                    //Check that the next square is in a direction away from the attacker
                    int deltaFleeX = nextStep.x - this.LocationMap.x;
                    int deltaFleeY = nextStep.y - this.LocationMap.y;

                    if (!relaxDirection)
                    {
                        if (deltaFleeX > 0 && deltaX > 0)
                        {
                            counter++;
                            //LogFile.Log.LogEntryDebug("MonsterThrowAndRunAI: Back away fail direction", LogDebugLevel.Low);
                            continue;
                        }
                        if (deltaFleeX < 0 && deltaX < 0)
                        {
                            counter++;
                            //LogFile.Log.LogEntryDebug("MonsterThrowAndRunAI: Back away fail direction", LogDebugLevel.Low);
                            continue;
                        }
                        if (deltaFleeY > 0 && deltaY > 0)
                        {
                            counter++;
                            //LogFile.Log.LogEntryDebug("MonsterThrowAndRunAI: Back away fail direction", LogDebugLevel.Low);
                            continue;
                        }
                        if (deltaFleeY < 0 && deltaY < 0)
                        {
                            counter++;
                            //LogFile.Log.LogEntryDebug("MonsterThrowAndRunAI: Back away fail direction", LogDebugLevel.Low);
                            continue;
                        }
                    }

                    //Check the square is empty
                    bool isEnterable = Game.Dungeon.MapSquareIsWalkable(this.LocationLevel, new Point(fleeX, fleeY));
                    if (!isEnterable)
                    {
                        counter++;
                        //LogFile.Log.LogEntryDebug("MonsterThrowAndRunAI: Back away fail enterable", LogDebugLevel.Low);
                        continue;
                    }

                    //Check the square is empty of creatures
                    SquareContents contents = Game.Dungeon.MapSquareContents(this.LocationLevel, new Point(fleeX, fleeY));
                    if (contents.monster != null)
                    {
                        counter++;
                        //LogFile.Log.LogEntryDebug("MonsterThrowAndRunAI: Back away fail blocked", LogDebugLevel.Low);
                        continue;
                    }


                    //Check that the target is visible from the square we are fleeing to
                    //This may prove to be too expensive

                    CreatureFOV projectedFOV = Game.Dungeon.CalculateCreatureFOV(this, nextStep);

                    if (!projectedFOV.CheckTileFOV(newTarget.LocationMap.x, newTarget.LocationMap.y))
                    {
                        counter++;
                        //LogFile.Log.LogEntryDebug("MonsterThrowAndRunAI: Back away fail fov", LogDebugLevel.Low);
                        continue;
                    }

                    //Otherwise we found it
                    goodPath = true;
                    break;
                } while (counter < totalFleeLoops);

                LogFile.Log.LogEntryDebug("Back away results. Count: " + counter + " Direction at: " + relaxDirectionAt + " Total: " + totalFleeLoops, LogDebugLevel.Low);

                //If we found a good path, walk it
                if (goodPath)
                {
                    MoveIntoSquare(nextStep);
                    SetHeadingToTarget(newTarget);
                }
                else if (WillAttack())
                {
                    //If not, don't back away and attack
                    //(target in FOV)
                    CombatResults result;

                    //Set heading to target
                    SetHeadingToTarget(newTarget);

                    if (newTarget == Game.Dungeon.Player)
                    {
                        result = AttackPlayer(newTarget as Player);
                    }
                    else
                    {
                        //It's a normal creature
                        result = AttackMonster(newTarget as Monster);
                    }

                    //Missile animation
                    Screen.Instance.DrawMissileAttack(this, newTarget, result, GetWeaponColor());
                }
            }

            //Close enough to fire. Not backing away (either far enough away or chose not to)
            else if (Utility.TestRange(this, newTarget, GetMissileRange()) && WillAttack())
            {
                //In range

                //Check FOV. If not in FOV, chase the player.
                if (!currentFOV.CheckTileFOV(newTarget.LocationMap.x, newTarget.LocationMap.y))
                {
                    ContinueChasing(newTarget);
                    return;
                }

                //Enforce a symmetry FOV
                if (newTarget == Game.Dungeon.Player && !playerFOV.CheckTileFOV(this.LocationMap))
                {
                    ContinueChasing(newTarget);
                    return;
                }

                //In preference they will use their special ability rather than fighting
                //If they don't have a special ability or choose not to use it will return false

                //Special abilities are defined in derived classes

                bool usingSpecial = UseSpecialAbility();

                if (!usingSpecial)
                {
                    //In FOV - fire at the player
                    CombatResults result;

                    //Set heading to target (only if we are a Pursuing creature, capable of adapting our heading)
                    if (WillPursue())
                    {
                        SetHeadingToTarget(newTarget);
                    }

                    if (newTarget == Game.Dungeon.Player)
                    {
                        result = AttackPlayer(newTarget as Player);
                    }
                    else
                    {
                        //It's a normal creature
                        result = AttackMonster(newTarget as Monster);
                    }

                    //Missile animation
                    Screen.Instance.DrawMissileAttack(this, newTarget, result, GetWeaponColor());
                }
            }

            //Not in range, chase the target
            else
            {
                ContinueChasing(newTarget);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Gets a target from the player. false showed an escape. otherwise target is the target selected.
        /// </summary>
        /// <param name="?"></param>
        /// <returns></returns>
        private bool GetTargetFromPlayer(Point start, out Point target, TargettingType type, int range, double spreadAngle, char confirmChar, CreatureFOV currentFOV)
        {
            //Turn targetting mode on the screen
            Screen.Instance.TargettingModeOn();
            Screen.Instance.Target = start;
            Screen.Instance.TargetType = type;
            Screen.Instance.TargetRange = range;
            Screen.Instance.TargetPermissiveAngle = spreadAngle;

            if ((range == -1 && currentFOV.CheckTileFOV(start.x, start.y))
                || Utility.TestRangeFOVForWeapon(Game.Dungeon.Player, start, range, currentFOV))
            {
                Screen.Instance.SetTargetInRange = true;
                SquareContents sqC = SetViewPanelToTargetAtSquare(start);
            }
            else
            {
                Screen.Instance.SetTargetInRange = false;
            }

            Game.MessageQueue.AddMessage("Find a target. " + confirmChar + " to confirm. ESC to exit.");
            Screen.Instance.Update();

            bool keepLooping = true;
            bool validFire = false;

            target = start;

            do
            {
                //Get direction from the user or 'z' to fire
                KeyPress userKey = Keyboard.WaitForKeyPress(true);

                Point direction = new Point();
                KeyModifier mod = KeyModifier.Arrow;
                bool validDirection = false;

                if (GetDirectionFromKeypress(userKey, out direction, out mod))
                {
                    //Valid direction
                    validDirection = true;
                }
                else
                {
                    //Look for firing
                    if (userKey.KeyCode == KeyCode.TCODK_CHAR)
                    {
                        char keyCode = (char)userKey.Character;
                        if(keyCode == confirmChar) {

                                validFire = true;
                                keepLooping = false;
                        }
                    }

                    if (userKey.KeyCode == KeyCode.TCODK_ESCAPE)
                    {
                        keepLooping = false;
                    }
                }

                //If direction, update the location and redraw

                if (validDirection)
                {
                    Point newPoint = new Point(target.x + direction.x, target.y + direction.y);

                    int level = Game.Dungeon.Player.LocationLevel;

                    if (newPoint.x < 0 || newPoint.x >= Game.Dungeon.Levels[level].width || newPoint.y < 0 || newPoint.y >= Game.Dungeon.Levels[level].height)
                        continue;

                    //Otherwise OK
                    target = newPoint;

                    if ((range == -1 && currentFOV.CheckTileFOV(newPoint.x, newPoint.y))
                        || Utility.TestRangeFOVForWeapon(Game.Dungeon.Player, newPoint, range, currentFOV))
                    {
                        Screen.Instance.SetTargetInRange = true;
                        SquareContents sqC = SetViewPanelToTargetAtSquare(target);
                    }
                    else
                        Screen.Instance.SetTargetInRange = false;

                    //Update screen
                    Screen.Instance.Target = newPoint;
                    Game.MessageQueue.AddMessage("Find a target. " + confirmChar + " to confirm. ESC to exit.");
                    Screen.Instance.Update();

                }
            } while (keepLooping);

            //Turn targetting mode off
            Screen.Instance.TargettingModeOff();
            Screen.Instance.Update();

            return validFire;
        }
Exemplo n.º 4
0
        private void CheckTargetInPlayerFOV(CreatureFOV playerFOV)
        {
            var targetCreature = Screen.Instance.CreatureToView;
            var targetItem = Screen.Instance.ItemToView;
            var targetFeature = Screen.Instance.FeatureToView;

            if (targetCreature == null && targetItem == null && targetFeature == null)
                return;

            if(targetCreature != null) {
                if(targetCreature.LocationLevel != Game.Dungeon.Player.LocationLevel) {
                    ResetViewPanel();
                    return;
                }
                if (!playerFOV.CheckTileFOV(targetCreature.LocationMap))
                {
                    ResetViewPanel();
                    return;
                }
            }

            if (targetItem != null)
            {
                if (targetItem.LocationLevel != Game.Dungeon.Player.LocationLevel)
                {
                    ResetViewPanel();
                    return;
                }
                if (!playerFOV.CheckTileFOV(targetItem.LocationMap))
                {
                    ResetViewPanel();
                    return;
                }
            }

            if (targetFeature != null)
            {
                if (targetFeature.LocationLevel != Game.Dungeon.Player.LocationLevel)
                {
                    ResetViewPanel();
                    return;
                }
                if (!playerFOV.CheckTileFOV(targetFeature.LocationMap))
                {
                    ResetViewPanel();
                    return;
                }
            }
        }
Exemplo n.º 5
0
        private void TargetItemsCloseToPlayer(double range, CreatureFOV currentFOV)
        {
            Player player = Game.Dungeon.Player;
            Point start = player.LocationMap;
            var candidates = Game.Dungeon.GetNearbyCreaturesInOrderOfRange(range, currentFOV, player.LocationLevel, player.LocationMap);
            var candidatesInFOV = candidates.Where(c => currentFOV.CheckTileFOV(c.Item2.LocationMap));

            if (candidatesInFOV.Count() == 0)
            {
                ResetViewPanel();
                return;
            }

            var hostiles = candidatesInFOV.Where(c => c.Item2.InPursuit());

            if(hostiles.Count() > 0)
                SetViewPanelToTargetAtSquare(hostiles.First().Item2.LocationMap);
            else
                SetViewPanelToTargetAtSquare(candidatesInFOV.First().Item2.LocationMap);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Let the user target something
        /// </summary>
        /// <returns></returns>
        private bool TargetAttack(out Point target, int range, TargettingType targetType, double spreadAngle, char confirmChar, CreatureFOV currentFOV)
        {
            Player player = Game.Dungeon.Player;

            //Start on the nearest creature
            Creature closeCreature = Game.Dungeon.FindClosestHostileCreatureInFOV(player);

            if (closeCreature == null)
            {
                var allCreatures = Game.Dungeon.FindClosestCreaturesInPlayerFOV();
                if (allCreatures.Any())
                    closeCreature = allCreatures.First();
            }

            //If no nearby creatures, start on the player
            if (closeCreature == null)
                closeCreature = Game.Dungeon.Player;

            Point startPoint;

            if (Utility.TestRange(Game.Dungeon.Player, closeCreature, range) || range == -1)
            {
                startPoint = new Point(closeCreature.LocationMap.x, closeCreature.LocationMap.y);
            }
            else
            {
                startPoint = new Point(player.LocationMap.x, player.LocationMap.y);
            }
            /*
            //Get the FOV from Dungeon (this also updates the map creature FOV state)
            TCODFov currentFOV = Game.Dungeon.CalculateCreatureFOV(player);

            Point startPoint;

            //Is that creature in FOV
            if (currentFOV.CheckTileFOV(closeCreature.LocationMap.x, closeCreature.LocationMap.y))
            {
                //If so, target
                startPoint = new Point(closeCreature.LocationMap.x, closeCreature.LocationMap.y);
            }
            else
            {
                //If not, target the PC
                startPoint = new Point(player.LocationMap.x, player.LocationMap.y);
            }
            */
            //Get the desired target from the player

            return GetTargetFromPlayer(startPoint, out target, targetType, range, spreadAngle, confirmChar, currentFOV);
        }
Exemplo n.º 7
0
 private bool TargetAttack(out Point target, TargettingType targetType, double spreadAngle, char confirmChar, CreatureFOV currentFOV)
 {
     return TargetAttack(out target, -1, targetType, spreadAngle, confirmChar, currentFOV);
 }