예제 #1
0
파일: Position.cs 프로젝트: ekolis/TriQuest
        /// <summary>
        /// Determines the absolute position of this position for a formation facing this direction.
        /// For instance, for a facing of west, the front right position would be located in the northwest.
        /// </summary>
        /// <param name="facing"></param>
        /// <returns></returns>
        public AbsolutePosition AsAbsolute(Direction facing)
        {
            if (facing == Direction.North)
            {
                return(AbsolutePosition.FromCoordinates(Column, Row));
            }
            if (facing == Direction.South)
            {
                return(AbsolutePosition.FromCoordinates(2 - Column, 2 - Row));
            }
            if (facing == Direction.East)
            {
                return(AbsolutePosition.FromCoordinates(2 - Row, Column));
            }
            if (facing == Direction.West)
            {
                return(AbsolutePosition.FromCoordinates(Row, 2 - Column));
            }

            throw new ArgumentException("Invalid facing specified, not north/south/east/west");
        }
예제 #2
0
파일: Map.cs 프로젝트: ekolis/TriQuest
        private void Fight(Tile attackerTile, Tile defenderTile)
        {
            var attackers = attackerTile.Formation;
            var defenders = defenderTile.Formation;

            if (attackers == null || defenders == null)
            {
                return;
            }

            int tileSize = 3;

            foreach (var kvp in attackers.CreaturePositions)
            {
                // who is attacking now?
                var attacker = attackers.CreaturePositions[kvp.Key];

                // is attacker blocked behind another attacker? then he can't attack
                bool             blocked = false;
                RelativePosition pos     = kvp.Key;
                while (true)
                {
                    var apos = pos.AsAbsolute(attackers.Facing);
                    apos = AbsolutePosition.FromCoordinates(apos.Column + attackers.Facing.DeltaX, apos.Row + attackers.Facing.DeltaY);
                    if (apos == null)
                    {
                        break;
                    }
                    pos = apos.RelativeTo(attackers.Facing);
                    if (pos != kvp.Key && attackers.CreaturePositions.ContainsKey(pos))
                    {
                        Log.Append("The " + attacker.Name + " is blocked by the " + attackers.CreaturePositions[pos].Name + ".");
                        blocked = true;
                        break;
                    }
                }
                if (blocked)
                {
                    continue;
                }

                // find nearest target
                Creature         defender = null;
                int              distance;
                var              absPos = kvp.Key.AsAbsolute(attackers.Facing);
                AbsolutePosition targetPos;
                if (attackers.Facing == Direction.North)
                {
                    distance  = absPos.Row;
                    targetPos = AbsolutePosition.FromCoordinates(absPos.Column, tileSize - 1);
                }
                else if (attackers.Facing == Direction.South)
                {
                    distance  = tileSize - 1 - absPos.Row;
                    targetPos = AbsolutePosition.FromCoordinates(absPos.Column, 0);
                }
                else if (attackers.Facing == Direction.East)
                {
                    distance  = tileSize - 1 - absPos.Column;
                    targetPos = AbsolutePosition.FromCoordinates(0, absPos.Column);
                }
                else if (attackers.Facing == Direction.West)
                {
                    distance  = absPos.Column;
                    targetPos = AbsolutePosition.FromCoordinates(tileSize - 1, absPos.Column);
                }
                else
                {
                    throw new Exception("Invalid formation facing, not north/south/east/west");
                }
                foreach (var distanceGroup in AbsolutePosition.All.GroupBy(pos2 => targetPos.DistanceTo(pos2)))
                {
                    var matches = distanceGroup.Where(pos2 =>
                    {
                        var relpos = pos2.RelativeTo(defenders.Facing);
                        return(defenders.CreaturePositions.ContainsKey(relpos) && defenders.CreaturePositions[relpos] != null);
                    });
                    if (matches.Any())
                    {
                        // multiple targets at same distance? pick one at random!
                        defender  = defenders.CreaturePositions[matches.Pick().RelativeTo(defenders.Facing)];
                        distance += distanceGroup.Key;
                        break;
                    }
                }

                // attaaaaack!
                if (defender == null)
                {
                    Log.Append("The " + attacker.Name + " has no one to attack.");                     // everyone's already dead!
                }
                else
                {
                    var    attack = attacker.Attack;
                    var    defense = defender.Defense;
                    var    atkBody = attacker.Body;
                    var    atkMind = attacker.Mind;
                    var    defBody = defender.Body;
                    var    defMind = defender.Mind;
                    int    atkStat, defStat, range;
                    string atkText;
                    if (atkBody - defBody >= atkMind - defMind)
                    {
                        // use physical attack
                        atkStat = atkBody;
                        defStat = defBody;
                        atkText = attacker.PhysicalAttackText;
                        range   = attacker.PhysicalAttackRange;
                    }
                    else
                    {
                        // use mental attack
                        atkStat = atkMind;
                        defStat = defMind;
                        atkText = attacker.MentalAttackText;
                        range   = attacker.MentalAttackRange;
                    }
                    var color = defenders == Heroes ? Color.Yellow : Color.White;

                    // accuracy penalty: 1/3 chance to miss for each subtile out of range
                    bool miss = false;
                    for (int i = 0; i < distance - range; i++)
                    {
                        if (Dice.Range(1, 3) == 1)
                        {
                            miss = true;
                            break;
                        }
                    }

                    string msg;
                    if (miss)
                    {
                        color = Color.Gray;
                        msg   = "The " + attacker.Name + " " + atkText + " the " + defender.Name + ", but misses (attack range " + range + ", target distance " + distance + ").";
                    }
                    else
                    {
                        var atkRoll = Dice.Roll(attack, atkStat);
                        var defRoll = Dice.Roll(defense, defStat);
                        var damage  = Math.Max(0, atkRoll - defRoll);
                        msg              = "The " + attacker.Name + " " + atkText + " the " + defender.Name + " (" + attack + "d" + atkStat + " vs. " + defense + "d" + defStat + ") for " + damage + " damage.";
                        defender.Health -= damage;
                        if (defender.Health <= 0)
                        {
                            msg += " The " + defender.Name + " is slain!";
                            if (defenders == Heroes)
                            {
                                color = Color.Red;
                            }
                            foreach (var p in RelativePosition.All)
                            {
                                if (defenders.CreaturePositions.ContainsKey(p) && defenders.CreaturePositions[p] == defender)
                                {
                                    KillCreature(defenderTile, p);                                     // he's dead, Jim...
                                }
                            }
                            if (!defenders.CreaturePositions.Any())
                            {
                                defenderTile.Formation = null;                                 // they're all dead, Dave...
                            }
                        }
                    }
                    Log.Append(msg, color);
                }
            }
        }