// Savage Worlds combat simulator, written by Zadmar.

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>

// Uncomment the following line to view the details of each fight (but set the NUMBER_OF_FIGHTS low).
//#define SHOW_MESSAGES

// Uncomment the following line to see every dice roll (this can get pretty spammy)
//#define SHOW_DICE_ROLLS

// How many fights do you wish to run?  Recommended 10000-100000, unless using SHOW_MESSAGES.
#define NUMBER_OF_FIGHTS 100000
//#define NUMBER_OF_FIGHTS 1

// Use the PAP rules for damage (d4/d12, d6/d10, etc) and toughness (straight Vigor).
//#define USE_PAP_DAMAGE_AND_TOUGHNESS

// House rule experiment: Armour gives double its normal bonus unless the attack hits with a raise.
//#define DOUBLE_ARMOUR_EXCEPT_ON_RAISE

// SWD: Cannot keep fighting after incapacitation, even if you get a raise.
#define DELUXE_INCAPACITATION

// Ablative armour can only absorb one wound per blow.
#define ABLATIVE_ARMOUR_ABSORBS_ONE_WOUND

// These penalties apply to ALL fighters using duel wield.  This is normally 2 for the primary 
// hand and 4 for the off-hand, but Two-Fisted lowers each penalty by 2, while Ambidextrous 
// lowers the off-hand penalty by 2.  Adjust these values to reflect such edges.
#define PENALTY_PRIMARY_HAND    2     /* Dual-wielders subtract this value from their primary hand */
#define PENALTY_OFFHAND         4     /* Dual-wielders subtract this value from their off-hand */

// Player 1 stats
#define PLAYER1_COUNT               1     /* How many of this character? */
#define PLAYER1_NAME                "Alpha"
#define PLAYER1_WILD_DIE            true  /* For Wild Cards */
#define PLAYER1_BENNIES             2     /* For Wild Cards */
#define PLAYER1_MAX_WOUNDS          3     /* For Wild Cards */
#define PLAYER1_NUMBER_OF_ATTACKS   1     /* Frenzy: 2, Rapid Attack: 3 */
#define PLAYER1_STRENGTH_DIE        8
#define PLAYER1_VIGOR_DIE           8
#define PLAYER1_AGILITY_DIE         6
#define PLAYER1_SPIRIT_DIE          6
#define PLAYER1_SMARTS_DIE          6
#define PLAYER1_INTIMIDATION_DIE    6     /* Intimidation skill */
#define PLAYER1_FIGHTING_DIE        8     /* Fighting skill */
#define PLAYER1_WEAPON_DIE          8     /* The damage die */
#define PLAYER1_WEAPON2_DIE         4     /* The offhand damage die */
#define PLAYER1_ATTACK_BONUS        0     /* Attack bonus for primary hand */
#define PLAYER1_ATTACK2_BONUS       0     /* Attack bonus for off hand */
#define PLAYER1_BONUS_DIE           6     /* The bonus damage die */
#define PLAYER1_BONUS2_DIE          6     /* The offhand bonus damage die */
#define PLAYER1_DAMAGE_BONUS        0     /* Flat bonus, eg +2 */
#define PLAYER1_PARRY_MODIFIER      0     /* +1 for a buckler, -1 for a greatsword, etc */
#define PLAYER1_ARMOUR              0     /* If you're using P&P, manually add this to parry penalty */
#define PLAYER1_ARMOUR_ON_RAISE     0     /* Usually the same as armour */
#define PLAYER1_AP                  0     /* AP with primary hand */
#define PLAYER1_AP2                 0     /* AP with off hand */
#define PLAYER1_SOAK_BONUS          0     /* +X Soak bonus */
#define PLAYER1_BENNIES_FOR_UNSHAKE true  /* Spend bennies to remove Shaken status */
#define PLAYER1_BENNIES_FOR_ACTION  true  /* Spend bennies to act if Shaken roll was just a success */
#define PLAYER1_BENNIES_FOR_SOAK    true  /* Spend bennies to soak wounds */
#define PLAYER1_WILD_ATTACK         false /* +2 to hit, +2 damage, -2 parry */
#define PLAYER1_DUAL_WIELD          false /* Both weapons are assumed to be the same */
#define PLAYER1_TWO_HANDED          false /* Custom edge: +1 to hit, inflict +1 damage on a raise */
#define PLAYER1_EXTRA_ATTACK        false /* Custom edge: Wild Die is treated as an extra attack */
#define PLAYER1_BERSERK             false /* Berserk edge: +2 hit/dam/toughness, -2 parry, and ignore wounds */
#define PLAYER1_COMBAT_REFLEXES     false /* +2 to recover from Shaken */
#define PLAYER1_HEADSHOT            false /* -4 attack, +4 damage */
#define PLAYER1_GIANT_KILLER        false /* +d6 vs opponent */
#define PLAYER1_HARDY               false /* Shaken isn't upgraded */
#define PLAYER1_UNSHAKABLE          false /* Cannot be shaken */
#define PLAYER1_IMP_UNSHAKABLE      false /* Cannot be shaken on wound */
#define PLAYER1_COUNTERATTACK       false /* Counterattack on miss at -2 */
#define PLAYER1_IMP_COUNTERATTACK   false /* Counterattack on miss at -0 */
#define PLAYER1_SWEEP               false /* Primary hand uses a sweep at -2 */
#define PLAYER1_IMP_SWEEP           false /* Primary hand uses a sweep at -0 */
#define PLAYER1_FIRST_STRIKE        false /* Assume the fighters start a few inches apart */
#define PLAYER1_REACH               false /* Assume they move out of reach after attacking */
#define PLAYER1_NEVER_MISS          false /* Custom edge: Half damage if it would have missed */
#define PLAYER1_DEFEND_WHEN_MOVE    false /* Uses 'Defend' when approaching the enemy */
#define PLAYER1_INTIMIDATE          false /* Uses Intimidate instead of walking into First Strike */
#define PLAYER1_ABLATIVE_ARMOUR     false /* Armour absorbs wounds */

// Player 2 stats
#define PLAYER2_COUNT               1     /* How many of this character? */
#define PLAYER2_NAME                "Beta"
#define PLAYER2_WILD_DIE            true  /* For Wild Cards */
#define PLAYER2_BENNIES             2     /* For Wild Cards */
#define PLAYER2_MAX_WOUNDS          3     /* For Wild Cards */
#define PLAYER2_NUMBER_OF_ATTACKS   1     /* Frenzy: 2, Rapid Attack: 3 */
#define PLAYER2_STRENGTH_DIE        8
#define PLAYER2_VIGOR_DIE           8
#define PLAYER2_AGILITY_DIE         6
#define PLAYER2_SPIRIT_DIE          6
#define PLAYER2_SMARTS_DIE          6
#define PLAYER2_INTIMIDATION_DIE    6     /* Intimidation skill */
#define PLAYER2_FIGHTING_DIE        8     /* Fighting skill */
#define PLAYER2_WEAPON_DIE          8     /* The damage die */
#define PLAYER2_WEAPON2_DIE         4     /* The offhand damage die */
#define PLAYER2_ATTACK_BONUS        0     /* Attack bonus for primary hand */
#define PLAYER2_ATTACK2_BONUS       0     /* Attack bonus for off hand */
#define PLAYER2_BONUS_DIE           6     /* The bonus damage die */
#define PLAYER2_BONUS2_DIE          6     /* The offhand bonus damage die */
#define PLAYER2_DAMAGE_BONUS        0     /* Flat bonus, eg +2 */
#define PLAYER2_PARRY_MODIFIER      0     /* +1 for a buckler, -1 for a greatsword, etc */
#define PLAYER2_ARMOUR              0     /* If you're using P&P, manually add this to parry penalty */
#define PLAYER2_ARMOUR_ON_RAISE     0     /* Usually the same as armour */
#define PLAYER2_AP                  0     /* AP with primary hand */
#define PLAYER2_AP2                 0     /* AP with off hand */
#define PLAYER2_SOAK_BONUS          0     /* +X Soak bonus */
#define PLAYER2_BENNIES_FOR_UNSHAKE true  /* Spend bennies to remove Shaken status */
#define PLAYER2_BENNIES_FOR_ACTION  true  /* Spend bennies to act if Shaken roll was just a success */
#define PLAYER2_BENNIES_FOR_SOAK    true  /* Spend bennies to soak wounds */
#define PLAYER2_WILD_ATTACK         false /* +2 to hit, +2 damage, -2 parry */
#define PLAYER2_DUAL_WIELD          false /* Both weapons are assumed to be the same */
#define PLAYER2_TWO_HANDED          false /* Custom edge: +1 to hit, inflict +1 damage on a raise */
#define PLAYER2_EXTRA_ATTACK        false /* Custom edge: Wild Die is treated as an extra attack */
#define PLAYER2_BERSERK             false /* Berserk edge: +2 hit/dam/toughness, -2 parry, and ignore wounds */
#define PLAYER2_COMBAT_REFLEXES     false /* +2 to recover from Shaken */
#define PLAYER2_HEADSHOT            false /* -4 attack, +4 damage */
#define PLAYER2_GIANT_KILLER        false /* +d6 vs opponent */
#define PLAYER2_HARDY               false /* Shaken isn't upgraded */
#define PLAYER2_UNSHAKABLE          false /* Cannot be shaken */
#define PLAYER2_IMP_UNSHAKABLE      false /* Cannot be shaken on wound */
#define PLAYER2_COUNTERATTACK       false /* Counterattack on miss at -2 */
#define PLAYER2_IMP_COUNTERATTACK   false /* Counterattack on miss at -0 */
#define PLAYER2_SWEEP               false /* Primary hand uses a sweep at -2 */
#define PLAYER2_IMP_SWEEP           false /* Primary hand uses a sweep at -0 */
#define PLAYER2_FIRST_STRIKE        false /* Assume the fighters start a few inches apart */
#define PLAYER2_REACH               false /* Assume they move out of reach after attacking */
#define PLAYER2_NEVER_MISS          false /* Custom edge: Half damage if it would have missed */
#define PLAYER2_DEFEND_WHEN_MOVE    false /* Uses 'Defend' when approaching the enemy */
#define PLAYER2_INTIMIDATE          false /* Uses Intimidate instead of walking into First Strike */
#define PLAYER2_ABLATIVE_ARMOUR     false /* Armour absorbs wounds */





std::string GetString( int aValue )
{
   char buf[256];
   sprintf(buf, "%d", aValue);
   return buf;
}

int RandomNumber( int aMax )
{
   return (rand() % aMax + 1);
}

int LowestOf( int aFirst, int aSecond )
{
   return aFirst < aSecond ? aFirst : aSecond;
}

int RollDice( int aSides )
{
   int Result = (rand() % aSides + 1);
   if ( Result == aSides )
   {
#ifdef SHOW_DICE_ROLLS
      std::cout << "Rolled a d" << GetString(aSides) << ": " << GetString(Result) << " - ACE, roll again!" << std::endl;
#endif // SHOW_DICE_ROLLS
      Result += RollDice(aSides);
   }
#ifdef SHOW_DICE_ROLLS
   else std::cout << "Rolled a d" << GetString(aSides) << ": " << GetString(Result) << std::endl;
#endif // SHOW_DICE_ROLLS
   return Result;
}

struct character_t
{
   std::string Name;
   bool        bWildDie;
   int         Side;
   int         Bennies;
   int         MaxWounds;
   int         NumberOfAttacks;
   int         Strength;
   int         Vigor;
   int         Agility;
   int         Spirit;
   int         Smarts;
   int         Intimidation;
   int         Fighting;
   int         Weapon;
   int         Weapon2;
   int         Attack;
   int         Attack2;
   int         Bonus;
   int         Bonus2;
   int         Damage;
   bool        bBenniesForUnshake;
   bool        bBenniesForAction;
   bool        bBenniesForSoak;
   bool        bWildAttack;
   bool        bDualWield;
   bool        bTwoHanded;
   bool        bExtraAttack;
   bool        bBerserk;
   bool        bCombatReflexes;
   bool        bHeadshot;
   bool        bGiantKiller;
   bool        bHardy;
   bool        bUnshakable;
   bool        bImprovedUnshakable;
   bool        bCounterattack;
   bool        bImprovedCounterattack;
   bool        bHasCounterattacked;
   bool        bSweep;
   bool        bImprovedSweep;
   bool        bFirstStrike;
   bool        bReach;
   bool        bNeverMiss;
   bool        bDefendWhenMove;
   bool        bDefend;
   bool        bIntimidate;
   bool        bIntimidating; // +2 bonus.
   int         Parry;
   int         Toughness;
   int         Armour;
   int         ArmourOnRaise;
   bool        bAblativeArmour;
   int         AP;
   int         AP2;
   int         Soak;
   int         Wounds;
   int         GangUp;
   bool        bIsWild;
   bool        bIsBerserk;
   bool        bShaken;
   bool        bCannotAct;
   bool        bDead;
};

static character_t Player1[PLAYER1_COUNT];
static character_t Player2[PLAYER2_COUNT];

int RollDiceWild( character_t *pCharacter, int aSides )
{
   int Result1 = RollDice(aSides);
   int Result2 = pCharacter->bWildDie ? RollDice(6) : 0;
   return Result1 > Result2 ? Result1 : Result2;
}

bool UseBenny( character_t *pCharacter )
{
   bool bResult = false;

   if ( pCharacter->Bennies > 0 )
   {
      --pCharacter->Bennies;
      bResult = true;
   }

   return bResult;
}

void RecoverFromShaken( character_t *pAttacker, character_t *pDefender, bool &bAdjacent )
{
   if ( pAttacker->bShaken )
   {
#ifdef SHOW_MESSAGES
      std::cout << pAttacker->Name << " tries to recover from being shaken..." << std::endl;
#endif // SHOW_MESSAGES

      int SpiritRoll = RollDiceWild(pAttacker, pAttacker->Spirit);
      std::string Result = "Spirit roll of " + GetString(SpiritRoll);

      if ( pAttacker->bCombatReflexes )
      {
         Result += "+2";
         SpiritRoll += 2;
      }

      if ( pAttacker->Wounds > 0 && !pAttacker->bIsBerserk )
      {
         Result += "-";
         Result += GetString(pAttacker->Wounds);
         SpiritRoll -= pAttacker->Wounds;
         Result += "=";
         Result += GetString(SpiritRoll);
      }

      if ( SpiritRoll >= 8 )
      {
#ifdef SHOW_MESSAGES
         std::cout << Result << " vs TN4 = SUCCESS WITH RAISE" << std::endl;
#endif // SHOW_MESSAGES
         pAttacker->bShaken = false;
      }
      else if ( SpiritRoll >= 4 )
      {
#ifdef SHOW_MESSAGES
         std::cout << Result << " vs TN4 = SUCCESS" << std::endl;
#endif // SHOW_MESSAGES

         if ( pAttacker->bBenniesForAction && UseBenny(pAttacker) )
         {
            pAttacker->bShaken = false;
#ifdef SHOW_MESSAGES
            std::cout << pAttacker->Name << " spends a benny to act this round." << std::endl;
#endif // SHOW_MESSAGES
         }
         else // Didn't spend a benny.
         {
            pAttacker->bShaken = false;
            pAttacker->bCannotAct = true;

            // Retreat to take advantage of reach and First Strike.
            if ( pAttacker->bFirstStrike && bAdjacent && pAttacker->bReach && !pDefender->bReach )
            {
#ifdef SHOW_MESSAGES
               std::cout << pAttacker->Name << " retreats 1\" (no free attack due to weapon reach)." << std::endl;
#endif // SHOW_MESSAGES

               // Retreat so that they can use First Strike next turn.
               bAdjacent = false;
            }
            return;
         }
      }
      else // SpiritRoll < 4
      {
#ifdef SHOW_MESSAGES
         std::cout << Result << " vs TN4 = FAILURE" << std::endl;
#endif // SHOW_MESSAGES

         if ( pAttacker->bBenniesForUnshake && UseBenny(pAttacker) )
         {
#ifdef SHOW_MESSAGES
            std::cout << pAttacker->Name << " spends a benny to remove Shaken status." << std::endl;
#endif // SHOW_MESSAGES
            pAttacker->bShaken = false;
         }
         else // Didn't spend a benny.
            return;
      }
   }
}

bool ExecuteAttack( character_t *pAttacker, character_t *pDefender, int RawAttackRoll, int aPenalty, bool bOffhand, bool bCounterattack, bool bFirstStrike, bool bSweep )
{
   bool bResult = true;
#ifdef SHOW_MESSAGES
   if ( bSweep )
      ; // No message.
   else if ( bOffhand )
      std::cout << pAttacker->Name << " launches an offhand attack..." << std::endl;
   else if ( bCounterattack )
      std::cout << pAttacker->Name << " launches a counterattack..." << std::endl;
   else if ( bFirstStrike )
      std::cout << pAttacker->Name << " interrupts with a First Strike attack..." << std::endl;
   else // Normal attack.
      std::cout << pAttacker->Name << " launches an attack..." << std::endl;
#endif // SHOW_MESSAGES
   int WeaponDamage = bOffhand ? pAttacker->Weapon2 : pAttacker->Weapon;
   int AttackerWoundPenalty = pAttacker->bIsBerserk ? 0 : pAttacker->Wounds;
   int DefenderWoundPenalty = pDefender->bIsBerserk ? 0 : pDefender->Wounds;
   int AttackRoll = RawAttackRoll - AttackerWoundPenalty - aPenalty + (2*pAttacker->bIsBerserk);
   if ( !bCounterattack && !bFirstStrike)
      AttackRoll += (2*pAttacker->bWildAttack);
   AttackRoll += (2*pAttacker->bIntimidating);

   int AttackBonus = bOffhand ? pAttacker->Attack2 : pAttacker->Attack;
   AttackBonus += pAttacker->GangUp;
   AttackRoll += AttackBonus;

   std::string AttackText = "Fighting roll of " + GetString(RawAttackRoll);
   if ( AttackerWoundPenalty + aPenalty > 0 )
   {
      if ( pAttacker->bWildAttack && !bCounterattack && !bFirstStrike )
         AttackText += "+2";
      if ( pAttacker->bIsBerserk )
         AttackText += "+2";
      if ( pAttacker->bIntimidating )
         AttackText += "+2";
      if ( AttackBonus )
         AttackText += "+" + GetString(AttackBonus);

      AttackText += "-";
      AttackText += GetString(AttackerWoundPenalty + aPenalty);
      AttackText += "=";
      AttackText += GetString(AttackRoll);
   }
   else if ( (!bCounterattack && !bFirstStrike && pAttacker->bWildAttack) || 
      pAttacker->bIsBerserk || pAttacker->bIntimidating || AttackBonus > 0 )
   {
      if ( pAttacker->bWildAttack && !bCounterattack && !bFirstStrike )
         AttackText += "+2";
      if ( pAttacker->bIsBerserk )
         AttackText += "+2";
      if ( pAttacker->bIntimidating )
         AttackText += "+2";
      if ( AttackBonus )
         AttackText += "+" + GetString(AttackBonus);

      AttackText += "=";
      AttackText += GetString(AttackRoll);
   }

   // Clear the intimidation bonus.
   pAttacker->bIntimidating = false;

   if ( pAttacker->bHeadshot )
   {
      AttackRoll -= 4;
      AttackText += "-4=";
      AttackText += GetString(AttackRoll);
   }

   // Special Two-Handed edge bonus: +1 to attack roll
   if ( pAttacker->bTwoHanded )
   {
      AttackText += "+1=";
      AttackText += GetString(++AttackRoll);
   }

   if ( ((RawAttackRoll > 1 || !pAttacker->bWildDie) && AttackRoll >= pDefender->Parry) || pAttacker->bNeverMiss )
   {
      bool bAceDamage = (AttackRoll >= pDefender->Parry + 4);
      bool bHalfDamage = (AttackRoll < pDefender->Parry);
      bool bNoDamage = (bHalfDamage && RawAttackRoll == 1);// || AttackRoll <= 1;

#ifdef SHOW_MESSAGES
      if ( bAceDamage )
         std::cout << AttackText << " vs Parry of " << GetString(pDefender->Parry) << " = HIT WITH RAISE" << std::endl;
      else if ( bHalfDamage )
         std::cout << AttackText << " vs Parry of " << GetString(pDefender->Parry) << " = HIT (because they never miss)" << std::endl;
      else // Just a regular hit.
         std::cout << AttackText << " vs Parry of " << GetString(pDefender->Parry) << " = HIT" << std::endl;
#endif // SHOW_MESSAGES

      int DamageRoll = 0;
      if ( pAttacker->Strength >= WeaponDamage )
         DamageRoll += RollDice(pAttacker->Strength) + RollDice(WeaponDamage);
      else // Not strong enough to use the weapon, so it's only as effective as your Strength.
         DamageRoll += RollDice(pAttacker->Strength) + RollDice(pAttacker->Strength);

      // Add another d6.
      if ( pAttacker->bGiantKiller )
         DamageRoll += RollDice(6);

      // Add on any fixed bonus.
      DamageRoll += pAttacker->Damage;

      if ( bAceDamage )
      {
         if ( bOffhand )
            DamageRoll += RollDice(pAttacker->Bonus2);
         else // Primary hand.
            DamageRoll += RollDice(pAttacker->Bonus);

//#ifdef USE_PAP_DAMAGE_AND_TOUGHNESS
//         DamageRoll += RollDice(16 - WeaponDamage);
//#else // Just use the normal +d6 damage when you hit on a raise.
//         DamageRoll += RollDice(6);
//#endif // USE_PAP_DAMAGE_AND_TOUGHNESS
      }

      // Special Two-Handed edge bonus: +1 damage on a raise
      if ( pAttacker->bTwoHanded )
         DamageRoll += bAceDamage ? 1 : 0;

      if ( pAttacker->bWildAttack && !bCounterattack && !bFirstStrike )
         DamageRoll += 2;
      if ( pAttacker->bIsBerserk )
         DamageRoll += 2;
      if ( pAttacker->bHeadshot && !bHalfDamage )
         DamageRoll += 4;

      if ( bNoDamage )
         DamageRoll = 0;
      else if ( bHalfDamage )
         DamageRoll /= 2;

      std::string Result;

      int Armour = 0;
      if ( bAceDamage )
         Armour += pDefender->ArmourOnRaise;
      else // Not a raise.
         Armour += pDefender->Armour;
#ifdef DOUBLE_ARMOUR_EXCEPT_ON_RAISE
      if ( !bAceDamage )
         Armour *= 2;
#endif // DOUBLE_ARMOUR_EXCEPT_ON_RAISE

      int AP = bOffhand ? pAttacker->AP2 : pAttacker->AP;
      if ( AP > 0 && !bHalfDamage )
      {
         Armour -= AP;
         if ( Armour < 0 )
            Armour = 0;
      }

      int Toughness = pDefender->Toughness + Armour;
      std::string SoakText, AblativeText;

      if ( DamageRoll < Toughness )
         Result = "NO DAMAGE";
      else if ( DamageRoll < Toughness+4 )
      {
         if ( pDefender->bUnshakable )
         {
            Result = "UNSHAKABLE";
         }
         else if ( !pDefender->bShaken )
         {
            Result = "SHAKEN";
            pDefender->bShaken = true;
         }
         else if ( pDefender->bHardy )
         {
            Result = "HARDY";
         }
         else // They're already Shaken.
         {
            if ( pDefender->bAblativeArmour && pDefender->Armour > 0 )
            {
               Result = "0 WOUNDS (upgraded from Shaken, armour absorbed 1 wound)";
               --pDefender->Armour;
               --pDefender->ArmourOnRaise;
               if ( pDefender->ArmourOnRaise < 0 )
                  pDefender->ArmourOnRaise = 0;
            }
            else
            {
               Result = "1 WOUND (upgraded from Shaken)";
               int Successes = 0;
               if ( pDefender->bBenniesForSoak && UseBenny(pDefender) )
               {
                  int SoakRoll = RollDiceWild(pDefender, pDefender->Vigor);
                  SoakText = "Vigor roll of " + GetString(SoakRoll);

                  if ( pDefender->Wounds > 0 && !pDefender->bIsBerserk )
                  {
                     if ( pDefender->Soak > 0 )
                     {
                        SoakText += "+";
                        SoakText += GetString(pDefender->Soak);
                        SoakRoll += pDefender->Soak;
                     }

                     SoakText += "-";
                     SoakText += GetString(pDefender->Wounds);
                     SoakRoll -= pDefender->Wounds;

                     SoakText += "=";
                     SoakText += GetString(SoakRoll);
                  }
                  else if ( pDefender->Soak > 0 )
                  {
                     SoakText += "+";
                     SoakText += GetString(pDefender->Soak);
                     SoakRoll += pDefender->Soak;

                     SoakText += "=";
                     SoakText += GetString(SoakRoll);
                  }

                  Successes = SoakRoll/4;
                  if ( Successes == 0 )
                     SoakText += " vs TN4 = FAILURE";
                  else if ( Successes == 1 )
                     SoakText += " vs TN4 = SUCCESS (Soaks the wound, removes Shaken)";
                  else if ( Successes == 2 )
                     SoakText += " vs TN4 = SUCCESS WITH RAISE (Soaks the wound, removes Shaken)";
                  else // Successes > 2
                     SoakText += " vs TN4 = SUCCESS WITH " + GetString(Successes-1) + " RAISES (Soaks the wound, removes Shaken)";
               }

               if ( Successes > 0 )
                  pDefender->bShaken = false;
               else if ( ++pDefender->Wounds > pDefender->MaxWounds )
                  Result += ", INCAPACITATED";
            }
         }
      }
      else // wound
      {
         if ( pDefender->bImprovedUnshakable )
         {
            Result = "UNSHAKABLE, ";
         }
         else if ( !pDefender->bShaken )
         {
            Result = "SHAKEN, ";
            pDefender->bShaken = true;
         }
         int Wounds = (DamageRoll - Toughness) / 4;

         if ( pDefender->bAblativeArmour )
         {
            int Reduction = LowestOf( Wounds, pDefender->Armour );
            if ( Reduction > 0 )
            {
#ifdef ABLATIVE_ARMOUR_ABSORBS_ONE_WOUND
               Reduction = 1;
#endif // ABLATIVE_ARMOUR_ABSORBS_ONE_WOUND

               AblativeText = " (armour absorbed ";
               AblativeText += GetString(Reduction);
               AblativeText += (Reduction == 1) ? " wound)" : " wounds)";
               Wounds -= Reduction;
               pDefender->Armour -= Reduction;
               pDefender->ArmourOnRaise -= Reduction;
               if ( pDefender->ArmourOnRaise < 0 )
                  pDefender->ArmourOnRaise = 0;
            }
         }

         Result += GetString(Wounds);
         Result += Wounds == 1 ? " WOUND" : " WOUNDS";

         int Successes = 0;
         if ( Wounds > 0 && pDefender->bBenniesForSoak && UseBenny(pDefender) )
         {
            int SoakRoll = RollDiceWild(pDefender, pDefender->Vigor);
            SoakText = "Vigor roll of " + GetString(SoakRoll);

            if ( pDefender->Wounds > 0 && !pDefender->bIsBerserk )
            {
               if ( pDefender->Soak > 0 )
               {
                  SoakText += "+";
                  SoakText += GetString(pDefender->Soak);
                  SoakRoll += pDefender->Soak;
               }

               SoakText += "-";
               SoakText += GetString(pDefender->Wounds);
               SoakRoll -= pDefender->Wounds;

               SoakText += "=";
               SoakText += GetString(SoakRoll);
            }
            else if ( pDefender->Soak > 0 )
            {
               SoakText += "+";
               SoakText += GetString(pDefender->Soak);
               SoakRoll += pDefender->Soak;

               SoakText += "=";
               SoakText += GetString(SoakRoll);
            }

            Successes = SoakRoll/4;
            if ( Successes == 0 )
               SoakText += " vs TN4 = FAILURE";
            else if ( Successes == 1 )
               SoakText += " vs TN4 = SUCCESS";
            else if ( Successes == 2 )
               SoakText += " vs TN4 = SUCCESS WITH RAISE";
            else // Successes > 2
               SoakText += " vs TN4 = SUCCESS WITH " + GetString(Successes-1) + " RAISES";

            if ( Successes >= Wounds )
            {
               pDefender->bShaken = false;
               if ( Wounds == 1 )
                  SoakText += " (Soaks the wound, removes Shaken)";
               else // Soaked multiple wounds.
                  SoakText += " (Soaks the " + GetString(Wounds) + " wounds, removes Shaken)";
               Wounds = 0;
            }
            else // Didn't soak everything.
            {
               if ( Successes == 1 )
                  SoakText += " (Soaks 1 wound)";
               else // Soaked multiple wounds.
                  SoakText += " (Soaks " + GetString(Successes) + " wounds)";

               Wounds -= Successes;
            }
         }

         pDefender->Wounds += Wounds;

         if ( pDefender->Wounds > pDefender->MaxWounds )
            Result += ", INCAPACITATED";
      }

#ifdef SHOW_MESSAGES
      std::cout << "Damage roll of " << GetString(DamageRoll);
      if ( bNoDamage )
         std::cout << " (from critical failure)";
      else if ( bHalfDamage )
         std::cout << " (halved)";
      std::cout << " vs Toughness of " << GetString(Toughness) << " = " << Result << AblativeText << std::endl;
#endif // SHOW_MESSAGES

      if ( !SoakText.empty() )
      {
#ifdef SHOW_MESSAGES
         std::cout << pDefender->Name << " spends a benny to try and Soak..." << std::endl;
         std::cout << SoakText << std::endl;
#endif // SHOW_MESSAGES
      }

      if ( DamageRoll >= Toughness )
      {
         if ( pDefender->bBerserk && !pDefender->bIsBerserk )
         {
#ifdef SHOW_MESSAGES
            std::cout << pDefender->Name << " attempts to go berserk..." << std::endl;
#endif // SHOW_MESSAGES

            int SmartsRoll = RollDiceWild(pDefender, pDefender->Smarts);
            int Penalty = pDefender->Wounds > 3 ? 3 : pDefender->Wounds;
            std::string Result = "Smarts roll of " + GetString(SmartsRoll);
            if ( Penalty > 0 )
            {
               Result += "-";
               Result += GetString(Penalty);
               SmartsRoll -= Penalty;
               Result += "=";
               Result += GetString(SmartsRoll);
            }

            if ( SmartsRoll >= 8 )
            {
#ifdef SHOW_MESSAGES
               std::cout << Result << " vs TN4 = SUCCESS WITH RAISE" << std::endl;
#endif // SHOW_MESSAGES
            }
            else if ( SmartsRoll >= 4 )
            {
#ifdef SHOW_MESSAGES
               std::cout << Result << " vs TN4 = SUCCESS" << std::endl;
#endif // SHOW_MESSAGES
            }
            else // SmartsRoll < 4
            {
#ifdef SHOW_MESSAGES
               std::cout << Result << " vs TN4 = FAILURE" << std::endl;
               std::cout << pDefender->Name << " goes berserk!" << std::endl;
#endif // SHOW_MESSAGES

               pDefender->bIsBerserk = true;
               pDefender->Parry -= 2;
               pDefender->Toughness += 2;
            }
         }
      }

      if ( pDefender->Wounds > pDefender->MaxWounds )
      {
         pDefender->Wounds = pDefender->MaxWounds; // Cannot actually have more than max wounds.

#ifdef SHOW_MESSAGES
         std::cout << pDefender->Name << " attempts to survive incapacitation..." << std::endl;
#endif // SHOW_MESSAGES

         // Recalculate the wound penalty because the wounds have now been applied.
         DefenderWoundPenalty = pDefender->bIsBerserk ? 0 : pDefender->Wounds;

         int RawVigorRoll = RollDiceWild(pDefender, pDefender->Vigor);
         int VigorRoll = RawVigorRoll - DefenderWoundPenalty;
         std::string Result = "Vigor roll of " + GetString(RawVigorRoll);
         if ( DefenderWoundPenalty > 0 )
            Result += "-" + GetString(DefenderWoundPenalty) + "=" + GetString(VigorRoll);

         if ( VigorRoll >= 8 )
         {
#ifdef DELUXE_INCAPACITATION
            pDefender->bDead = true;
#endif // DELUXE_INCAPACITATION

#ifdef SHOW_MESSAGES
            if ( pDefender->bWildDie && pDefender->MaxWounds >= 3 )
               std::cout << Result << " vs TN4 = SUCCESS WITH RAISE (just stunned)" << std::endl;
            else // Extra.
               std::cout << Result << " vs TN4 = SUCCESS WITH RAISE (superficial wounds)" << std::endl;
#endif // SHOW_MESSAGES

            // Extras are always out of the fight if incapacitated, even in SWEX.
            if ( !pDefender->bWildDie && pDefender->MaxWounds < 3 )
               pDefender->bDead = true;
         }
         else // They're out of the fight.
         {
#ifdef SHOW_MESSAGES
            if ( pDefender->bWildDie && pDefender->MaxWounds >= 3 )
            {
               if ( VigorRoll >= 4 )
                  std::cout << Result << " vs TN4 = SUCCESS (just knocked out)" << std::endl;
               else if ( RawVigorRoll == 1 )
                  std::cout << Result << " vs TN4 = CRITICAL FAILURE (instant death)" << std::endl;
               else // Normal failure
                  std::cout << Result << " vs TN4 = FAILURE (possibly dying)" << std::endl;
            }
            else // Extra.
            {
               if ( VigorRoll >= 4 )
                  std::cout << Result << " vs TN4 = SUCCESS (recovers later)" << std::endl;
               else // Normal failure
                  std::cout << Result << " vs TN4 = FAILURE (dead)" << std::endl;
            }
#endif // SHOW_MESSAGES
            pDefender->bDead = true;
         }
      }
   }
   else // Miss.
   {
#ifdef SHOW_MESSAGES
      if ( pAttacker->bWildDie && RawAttackRoll == 1 )
         std::cout << "Fighting roll of 1 = CRITICAL MISS" << std::endl;
      else // Not snake eyes.
         std::cout << AttackText << " vs Parry of " << GetString(pDefender->Parry) << " = MISS" << std::endl;
#endif // SHOW_MESSAGES
      bResult = false;
   }
   return bResult;
}

struct DiceSort
{
   bool operator()(int Start, int End )
   {
      return ( Start > End );
   }
};

bool ExecuteMultiAttack( character_t *pAttacker, character_t *pDefender, int NumberOfAttacks, int Penalty )
{
   if ( NumberOfAttacks >= 1 )
   {
      // Roll the attack dice, plus one wild die if appropriate.
      std::vector<int> DiceResults;

      if ( pAttacker->bWildDie )
         DiceResults.push_back(RollDice(6));

      for ( int i = 0; i < NumberOfAttacks; ++i )
         DiceResults.push_back(RollDice(pAttacker->Fighting));

      // Sort the results from highest to lowest.
      std::sort( DiceResults.begin(), DiceResults.end(), DiceSort() );

      // Treat the wild die as an extra attack?
      if ( pAttacker->bExtraAttack && pAttacker->bWildDie )
         NumberOfAttacks++;

      // Execute the attacks from highest to lowest, ignoring the last result.
      bool bSuccess = true;
      for ( int i = 0; i < NumberOfAttacks; ++i )
         bSuccess &= ExecuteAttack( pAttacker, pDefender, DiceResults.at(i), Penalty, false, false, false, false );

      // There's a counterattack if ANY attacks miss (confirmed by Clint).
      return bSuccess;
   }

   // If there was no attack, there can be no miss.
   return false;
}

void ExecuteCounterattack( character_t *pAttacker, character_t *pDefender )
{
   if ( pDefender->bCounterattack && !pDefender->bShaken && 
      !pDefender->bHasCounterattacked )
   {
      int Penalty = pDefender->bImprovedCounterattack ? 0 : 2;
      bool bSuccess = ExecuteAttack( pDefender, pAttacker, RollDiceWild(pDefender, pDefender->Fighting), Penalty, false, true, false, false );
      pDefender->bHasCounterattacked = true;

      // Counter the counterattack!
      if ( !bSuccess && pAttacker->bCounterattack && !pAttacker->bShaken && 
         !pAttacker->bHasCounterattacked )
      {
         int Penalty = pAttacker->bImprovedCounterattack ? 0 : 2;
         bSuccess = ExecuteAttack( pAttacker, pDefender, RollDiceWild(pAttacker, pAttacker->Fighting), Penalty, false, true, false, false );
         pAttacker->bHasCounterattacked = true;
      }
   }
}

void PerformAction( character_t *pAttacker, character_t *pDefender, bool &bAdjacent )
{
   // No attacks if we're using Defend.
   if ( pAttacker->bDefend )
   {
      pAttacker->bDefend = false;
      pAttacker->Parry -= 2;
#ifdef SHOW_MESSAGES
      std::cout << pAttacker->Name << " stops using the 'Defend' maneuver (Parry returns to " << GetString(pAttacker->Parry) << ")." << std::endl;
#endif // SHOW_MESSAGES
   }

   // Stop the Wild Attack.
   if ( pAttacker->bIsWild )
   {
      pAttacker->bIsWild = false;
      pAttacker->Parry += 2;
#ifdef SHOW_MESSAGES
      std::cout << pAttacker->Name << " stops using Wild Attack (Parry returns to " << GetString(pAttacker->Parry) << ")." << std::endl;
#endif // SHOW_MESSAGES
   }

   bool bRecoverAttempt = pAttacker->bShaken;
   if ( pAttacker->bShaken )
      RecoverFromShaken(pAttacker, pDefender, bAdjacent);

   // The attacker is Shaken and cannot continue the fight.
   if ( pAttacker->bShaken || pAttacker->bCannotAct )
   {
      // Retreat to take advantage of reach and First Strike.
      if ( !pAttacker->bDead && pAttacker->bFirstStrike && bAdjacent && pAttacker->bReach && !pDefender->bReach )
      {
#ifdef SHOW_MESSAGES
         std::cout << pAttacker->Name << " retreats 1\" (no free attack due to weapon reach)." << std::endl;
#endif // SHOW_MESSAGES

         // Retreat so that they can use First Strike next turn.
         bAdjacent = false;
      }

      if ( pAttacker->bCannotAct )
      {
#ifdef SHOW_MESSAGES
          std::cout << pAttacker->Name << " only got a success when recovering from Shaken, no further actions." << std::endl;
#endif // SHOW_MESSAGES
      }

      pAttacker->bCannotAct = false;
      return;
   }

   // If you don't have reach, you trigger First Strike if they have it.
   if ( !pAttacker->bReach && !bAdjacent && pDefender->bFirstStrike && !pDefender->bShaken )
   {
      // Some characters will use 'Defend' in this situation.
      if ( !pAttacker->bShaken && pAttacker->bDefendWhenMove && !pAttacker->bDefend )
      {
         pAttacker->bDefend = true;
         pAttacker->Parry += 2;
#ifdef SHOW_MESSAGES
         std::cout << pAttacker->Name << " is now using the 'Defend' maneuver (Parry increased to " << GetString(pAttacker->Parry) << ")." << std::endl;
#endif // SHOW_MESSAGES
      }
      else if ( !pAttacker->bShaken && pAttacker->bIntimidate )
      {
         int FirstRoll = RollDiceWild(pAttacker, pAttacker->Intimidation);
         int FirstResult = FirstRoll + (2*pAttacker->bIntimidating);
         std::string FirstText(GetString(FirstRoll));
         if ( pAttacker->bIntimidating || (pAttacker->Wounds > 0 && !pAttacker->bIsBerserk) )
         {
            if ( pAttacker->bIntimidating )
               FirstText += "+2";

            if ( pAttacker->Wounds > 0 && !pAttacker->bIsBerserk )
            {
               FirstText += "-";
               FirstText += GetString(pAttacker->Wounds);
               FirstResult -= pAttacker->Wounds;
            }

            FirstText += "=" + GetString(FirstResult);
         }

         int SecondRoll = RollDiceWild(pDefender, pDefender->Spirit);
         int SecondResult = SecondRoll + (2*pDefender->bIntimidating);
         std::string SecondText(GetString(SecondRoll));
         if ( pDefender->bIntimidating || (pDefender->Wounds > 0 && !pDefender->bIsBerserk) )
         {
            if ( pDefender->bIntimidating )
               SecondText += "+2";

            if ( pDefender->Wounds > 0 && !pDefender->bIsBerserk )
            {
               SecondText += "-";
               SecondText += GetString(pDefender->Wounds);
               SecondResult -= pDefender->Wounds;
            }

            SecondText += "=" + GetString(SecondResult);
         }

         bool bSuccess = (FirstResult > SecondRoll);
         bool bRaise = (FirstResult >= (SecondRoll+4));
#ifdef SHOW_MESSAGES
         std::cout << pAttacker->Name << " attempts to intimidate " << pDefender->Name << "..." << std::endl;
         std::string Result = "Intimidation roll of " + FirstText;
         Result += " opposed by " + SecondText;
         Result += bRaise ? " = RAISE (Shaken and +2 to next action)" : bSuccess ? " = SUCCESS (+2 to next action)" : " = FAILURE";
         std::cout << Result << std::endl;
#endif // SHOW_MESSAGES
         if ( bRaise )
            pDefender->bShaken = true;
         pAttacker->bIntimidating = bSuccess;
         return;
      }
      // As clarified by Clint, Wild Attack has to be declared at this point.
      else if ( !pAttacker->bCannotAct && !pAttacker->bShaken && pAttacker->bWildAttack && !pAttacker->bIsWild )
      {
         pAttacker->bIsWild = true;
         pAttacker->Parry -= 2;
#ifdef SHOW_MESSAGES
         std::cout << pAttacker->Name << " is now using Wild Attack (Parry reduced to " << GetString(pAttacker->Parry) << ")." << std::endl;
#endif // SHOW_MESSAGES
      }
      else if ( pAttacker->bShaken )
      {
#ifdef SHOW_MESSAGES
         std::cout << pAttacker->Name << " doesn't advance, due to being Shaken." << std::endl;
#endif // SHOW_MESSAGES
         return;
      }

#ifdef SHOW_MESSAGES
      std::cout << pAttacker->Name << " moves adjacent to " << pDefender->Name << "." << std::endl;
#endif // SHOW_MESSAGES

      // If the First Strike misses, it can trigger Counterattack.
      if ( !ExecuteAttack( pDefender, pAttacker, RollDiceWild(pDefender, pDefender->Fighting), 0, false, false, true, false ) )
      {
         if ( !pAttacker->bShaken )
            ExecuteCounterattack( pDefender, pAttacker );
      }

      // They're right next to each other now.
      bAdjacent = true;
   }
   // As clarified by Clint, Wild Attack has to be declared at this point.
   else if ( !pAttacker->bCannotAct && !pAttacker->bShaken && pAttacker->bWildAttack && !pAttacker->bIsWild )
   {
      pAttacker->bIsWild = true;
      pAttacker->Parry -= 2;
#ifdef SHOW_MESSAGES
      std::cout << pAttacker->Name << " is now using Wild Attack (Parry reduced to " << GetString(pAttacker->Parry) << ")." << std::endl;
#endif // SHOW_MESSAGES
   }

   // Make sure you move adjacent initially, even if there's no First Strike going on.
   if ( !pAttacker->bReach && !bAdjacent )
   {
      // Retreat to take advantage of reach and First Strike.
      if ( !pAttacker->bDead && pAttacker->bFirstStrike && bAdjacent && pAttacker->bReach && !pDefender->bReach )
      {
#ifdef SHOW_MESSAGES
         std::cout << pAttacker->Name << " retreats 1\" (no free attack due to weapon reach)." << std::endl;
#endif // SHOW_MESSAGES

         // Retreat so that they can use First Strike next turn.
         bAdjacent = false;
      }

#ifdef SHOW_MESSAGES
      std::cout << pAttacker->Name << " moves adjacent to " << pDefender->Name << "." << std::endl;
#endif // SHOW_MESSAGES

      // They're right next to each other now.
      bAdjacent = true;
   }

   // If we didn't yet attempt to recover from being Shaken, we can try now, 
   // because the attacker has only had a free action (movement).
   if ( !bRecoverAttempt )
      RecoverFromShaken(pAttacker, pDefender, bAdjacent);

   // The attacker is Shaken and cannot continue the fight.
   if ( pAttacker->bShaken || pAttacker->bCannotAct )
   {
      if ( pAttacker->bCannotAct )
      {
#ifdef SHOW_MESSAGES
          std::cout << pAttacker->Name << " only got a success when recovering from Shaken, no further actions." << std::endl;
#endif // SHOW_MESSAGES
      }

      pAttacker->bCannotAct = false;
      return;
   }

   // No attacks if we're using Defend.
   if ( pAttacker->bDefend )
      return;

   bool bSuccess = false;
   if ( pAttacker->bSweep )
   {
#ifdef SHOW_MESSAGES
      std::cout << pAttacker->Name << " launches a sweep attack..." << std::endl;
#endif // SHOW_MESSAGES

      // Find the appropriate enemy list.
      character_t *pTarget = Player1;
      int Max = PLAYER1_COUNT;
      if ( pTarget->Side == pAttacker->Side )
      {
         pTarget = Player2;
         Max = PLAYER2_COUNT;
      }

      int Penalty = PENALTY_PRIMARY_HAND + (pAttacker->bImprovedSweep ? 0 : 2);
      int AttackRoll = RollDiceWild(pAttacker, pAttacker->Fighting);
      for ( int i = 0; i < Max; ++i )
      {
         if ( !pAttacker->bDead && !pTarget[i].bDead )
         {
            // Perform their primary attack/s
            bSuccess = ExecuteAttack( pAttacker, &pTarget[i], AttackRoll, Penalty, false, false, false, true );

            // If it's a miss, execute a counterattack.
            if ( !bSuccess )
               ExecuteCounterattack( pAttacker, &pTarget[i] );
         }
      }

      // It's possible to have an additional attack with the off hand.
      if ( !pAttacker->bDead && pAttacker->bDualWield )
      {
         for ( int i = 0; i < Max; ++i )
         {
            if ( !pTarget[i].bDead )
            {
               // Perform their offhand attack.
               bSuccess = ExecuteAttack( pAttacker, &pTarget[i], RollDiceWild(pAttacker, pAttacker->Fighting), PENALTY_OFFHAND, true, false, false, false ); // Secondary hand

               // If it's a miss, execute a counterattack.
               if ( !bSuccess )
                  ExecuteCounterattack( pAttacker, &pTarget[i] );

               // The offhand attack can only hit one target.
               break;
            }
         }
      }

      // We don't need to handle the counterattack separately, we've already dealt with it.
      bSuccess = true;
   }
   else if ( pAttacker->bDualWield )
   {
      // Perform their primary attack/s
      bSuccess = ExecuteMultiAttack( pAttacker, pDefender, pAttacker->NumberOfAttacks, PENALTY_PRIMARY_HAND );

      if ( !bSuccess )
      {
         // If it's a miss, execute a counterattack.
         ExecuteCounterattack( pAttacker, pDefender );
         bSuccess = true;
      }

      // Perform their offhand attack.
      if ( !pAttacker->bDead && !pAttacker->bShaken && !pDefender->bDead )
         bSuccess = ExecuteAttack( pAttacker, pDefender, RollDiceWild(pAttacker, pAttacker->Fighting), PENALTY_OFFHAND, true, false, false, false ); // Secondary hand
   }
   else // Only fighting with main hand.
   {
      // Perform their primary attack/s
      bSuccess = ExecuteMultiAttack( pAttacker, pDefender, pAttacker->NumberOfAttacks, 0 );
   }

   // If it's a miss, execute a counterattack.
   if ( !bSuccess )
      ExecuteCounterattack( pAttacker, pDefender );

   // Retreat to take advantage of reach and First Strike.
   if ( !pAttacker->bDead && pAttacker->bFirstStrike && bAdjacent && pAttacker->bReach && !pDefender->bReach )
   {
#ifdef SHOW_MESSAGES
      std::cout << pAttacker->Name << " retreats 1\" (no free attack due to weapon reach)." << std::endl;
#endif // SHOW_MESSAGES

      // Retreat so that they can use First Strike next turn.
      bAdjacent = false;
   }
}

int GameLoop( int &aRounds )
{
   for ( int i = 0; i < PLAYER1_COUNT; ++i )
   {
      Player1[i].Name = PLAYER1_NAME;
      if ( PLAYER1_COUNT > 1 )
         Player1[i].Name += GetString(i+1);
      Player1[i].bWildDie = PLAYER1_WILD_DIE;
      Player1[i].Side = 1;
      Player1[i].Bennies = PLAYER1_BENNIES;
      Player1[i].MaxWounds = PLAYER1_MAX_WOUNDS;
      Player1[i].NumberOfAttacks = PLAYER1_NUMBER_OF_ATTACKS;
      Player1[i].Strength = PLAYER1_STRENGTH_DIE;
      Player1[i].Vigor = PLAYER1_VIGOR_DIE;
      Player1[i].Agility = PLAYER1_AGILITY_DIE;
      Player1[i].Spirit = PLAYER1_SPIRIT_DIE;
      Player1[i].Smarts = PLAYER1_SMARTS_DIE;
      Player1[i].Intimidation = PLAYER1_INTIMIDATION_DIE;
      Player1[i].Fighting = PLAYER1_FIGHTING_DIE;
      Player1[i].Weapon = PLAYER1_WEAPON_DIE;
      Player1[i].Weapon2 = PLAYER1_WEAPON2_DIE;
      Player1[i].Attack = PLAYER1_ATTACK_BONUS;
      Player1[i].Attack2 = PLAYER1_ATTACK2_BONUS;
      Player1[i].Bonus = PLAYER1_BONUS_DIE;
      Player1[i].Bonus2 = PLAYER1_BONUS2_DIE;
      Player1[i].Damage = PLAYER1_DAMAGE_BONUS;
      Player1[i].bBenniesForUnshake = PLAYER1_BENNIES_FOR_UNSHAKE;
      Player1[i].bBenniesForAction = PLAYER1_BENNIES_FOR_ACTION;
      Player1[i].bBenniesForSoak = PLAYER1_BENNIES_FOR_SOAK;
      Player1[i].bWildAttack = PLAYER1_WILD_ATTACK;
      Player1[i].bDualWield = PLAYER1_DUAL_WIELD;
      Player1[i].bTwoHanded = PLAYER1_TWO_HANDED;
      Player1[i].bExtraAttack = PLAYER1_EXTRA_ATTACK;
      Player1[i].bBerserk = PLAYER1_BERSERK;
      Player1[i].bCombatReflexes = PLAYER1_COMBAT_REFLEXES;
      Player1[i].bHeadshot = PLAYER1_HEADSHOT;
      Player1[i].bGiantKiller = PLAYER1_GIANT_KILLER;
      Player1[i].bHardy = PLAYER1_HARDY;
      Player1[i].bUnshakable = PLAYER1_UNSHAKABLE;
      Player1[i].bImprovedUnshakable = PLAYER1_IMP_UNSHAKABLE;
      Player1[i].bCounterattack = PLAYER1_COUNTERATTACK;
      Player1[i].bImprovedCounterattack = PLAYER1_IMP_COUNTERATTACK;
      Player1[i].bHasCounterattacked = false;
      Player1[i].bSweep = PLAYER1_SWEEP;
      Player1[i].bImprovedSweep = PLAYER1_IMP_SWEEP;
      Player1[i].bFirstStrike = PLAYER1_FIRST_STRIKE;
      Player1[i].bReach = PLAYER1_REACH;
      Player1[i].bNeverMiss = PLAYER1_NEVER_MISS;
      Player1[i].bDefendWhenMove = PLAYER1_DEFEND_WHEN_MOVE;
      Player1[i].bDefend = false;
      Player1[i].bIntimidate = PLAYER1_INTIMIDATE;
      Player1[i].bIntimidating = false;
      Player1[i].Parry = (PLAYER1_FIGHTING_DIE/2)+2 + (PLAYER1_PARRY_MODIFIER);
#ifdef USE_PAP_DAMAGE_AND_TOUGHNESS
      Player1[i].Toughness = PLAYER1_VIGOR_DIE;
#else // Use the normal (Vigor/2)+2 toughness
      Player1[i].Toughness = (PLAYER1_VIGOR_DIE/2)+2;
#endif // USE_PAP_DAMAGE_AND_TOUGHNESS
      Player1[i].Armour = PLAYER1_ARMOUR;
      Player1[i].ArmourOnRaise = PLAYER1_ARMOUR_ON_RAISE;
      Player1[i].bAblativeArmour = PLAYER1_ABLATIVE_ARMOUR;
      Player1[i].AP = PLAYER1_AP;
      Player1[i].AP2 = PLAYER1_AP2;
      Player1[i].Soak = PLAYER1_SOAK_BONUS;
      Player1[i].Wounds = 0;
      Player1[i].GangUp = 0;
      Player1[i].bIsWild = false;
      Player1[i].bIsBerserk = false;
      Player1[i].bShaken = false;
      Player1[i].bCannotAct = false;
      Player1[i].bDead = false;
   }

   for ( int i = 0; i < PLAYER2_COUNT; ++i )
   {
      Player2[i].Name = PLAYER2_NAME;
      if ( PLAYER2_COUNT > 1 )
         Player2[i].Name += GetString(i+1);
      Player2[i].bWildDie = PLAYER2_WILD_DIE;
      Player2[i].Side = 2;
      Player2[i].Bennies = PLAYER2_BENNIES;
      Player2[i].MaxWounds = PLAYER2_MAX_WOUNDS;
      Player2[i].NumberOfAttacks = PLAYER2_NUMBER_OF_ATTACKS;
      Player2[i].Strength = PLAYER2_STRENGTH_DIE;
      Player2[i].Vigor = PLAYER2_VIGOR_DIE;
      Player2[i].Agility = PLAYER2_AGILITY_DIE;
      Player2[i].Spirit = PLAYER2_SPIRIT_DIE;
      Player2[i].Smarts = PLAYER2_SMARTS_DIE;
      Player2[i].Intimidation = PLAYER2_INTIMIDATION_DIE;
      Player2[i].Fighting = PLAYER2_FIGHTING_DIE;
      Player2[i].Weapon = PLAYER2_WEAPON_DIE;
      Player2[i].Weapon2 = PLAYER2_WEAPON2_DIE;
      Player2[i].Attack = PLAYER2_ATTACK_BONUS;
      Player2[i].Attack2 = PLAYER2_ATTACK2_BONUS;
      Player2[i].Bonus = PLAYER2_BONUS_DIE;
      Player2[i].Bonus2 = PLAYER2_BONUS2_DIE;
      Player2[i].Damage = PLAYER2_DAMAGE_BONUS;
      Player2[i].bBenniesForUnshake = PLAYER2_BENNIES_FOR_UNSHAKE;
      Player2[i].bBenniesForAction = PLAYER2_BENNIES_FOR_ACTION;
      Player2[i].bBenniesForSoak = PLAYER2_BENNIES_FOR_SOAK;
      Player2[i].bWildAttack = PLAYER2_WILD_ATTACK;
      Player2[i].bDualWield = PLAYER2_DUAL_WIELD;
      Player2[i].bTwoHanded = PLAYER2_TWO_HANDED;
      Player2[i].bExtraAttack = PLAYER2_EXTRA_ATTACK;
      Player2[i].bBerserk = PLAYER2_BERSERK;
      Player2[i].bCombatReflexes = PLAYER2_COMBAT_REFLEXES;
      Player2[i].bHeadshot = PLAYER2_HEADSHOT;
      Player2[i].bGiantKiller = PLAYER2_GIANT_KILLER;
      Player2[i].bHardy = PLAYER2_HARDY;
      Player2[i].bUnshakable = PLAYER2_UNSHAKABLE;
      Player2[i].bImprovedUnshakable = PLAYER2_IMP_UNSHAKABLE;
      Player2[i].bCounterattack = PLAYER2_COUNTERATTACK;
      Player2[i].bImprovedCounterattack = PLAYER2_IMP_COUNTERATTACK;
      Player2[i].bHasCounterattacked = false;
      Player2[i].bSweep = PLAYER2_SWEEP;
      Player2[i].bImprovedSweep = PLAYER2_IMP_SWEEP;
      Player2[i].bFirstStrike = PLAYER2_FIRST_STRIKE;
      Player2[i].bReach = PLAYER2_REACH;
      Player2[i].bNeverMiss = PLAYER2_NEVER_MISS;
      Player2[i].bDefendWhenMove = PLAYER2_DEFEND_WHEN_MOVE;
      Player2[i].bDefend = false;
      Player2[i].bIntimidate = PLAYER2_INTIMIDATE;
      Player2[i].bIntimidating = false;
      Player2[i].Parry = (PLAYER2_FIGHTING_DIE/2)+2 + (PLAYER2_PARRY_MODIFIER);
#ifdef USE_PAP_DAMAGE_AND_TOUGHNESS
      Player2[i].Toughness = PLAYER2_VIGOR_DIE;
#else // Use the normal (Vigor/2)+2 toughness
      Player2[i].Toughness = (PLAYER2_VIGOR_DIE/2)+2;
#endif // USE_PAP_DAMAGE_AND_TOUGHNESS
      Player2[i].Armour = PLAYER2_ARMOUR;
      Player2[i].ArmourOnRaise = PLAYER2_ARMOUR_ON_RAISE;
      Player2[i].bAblativeArmour = PLAYER2_ABLATIVE_ARMOUR;
      Player2[i].AP = PLAYER2_AP;
      Player2[i].AP2 = PLAYER2_AP2;
      Player2[i].Soak = PLAYER2_SOAK_BONUS;
      Player2[i].Wounds = 0;
      Player2[i].GangUp = 0;
      Player2[i].bIsWild = false;
      Player2[i].bIsBerserk = false;
      Player2[i].bShaken = false;
      Player2[i].bCannotAct = false;
      Player2[i].bDead = false;
   }

   int Round = 0;
   bool bPlayer1Alive = true, bPlayer2Alive = true;

   bool bAdjacent = false;
   while ( bPlayer1Alive && bPlayer2Alive )
   {
      ++Round;

      // Initiative
      character_t *pFirst = Player1, *pSecond = Player2;
      int FirstMax = PLAYER1_COUNT, SecondMax = PLAYER2_COUNT;
      int FirstGangUp = -1, SecondGangUp = -1;

      if ( RandomNumber(2) == 1 )
      {
         pFirst = Player2;
         pSecond = Player1;
         FirstMax = PLAYER2_COUNT;
         SecondMax = PLAYER1_COUNT;
      }

#ifdef SHOW_MESSAGES
      std::cout << ">>> ROUND " << GetString(Round) << ":" << std::endl;
#endif // SHOW_MESSAGES

      // If neither character has reach and only the first has First Strike, they go on hold.
      if ( !bAdjacent && !pFirst->bReach && !pSecond->bReach && pFirst->bFirstStrike && !pSecond->bFirstStrike )
      {
         bAdjacent = true;

#ifdef SHOW_MESSAGES
         std::cout << pFirst->Name << " goes on hold..." << std::endl;
         std::cout << pSecond->Name << " moves adjacent to " << pFirst->Name << "." << std::endl;
#endif // SHOW_MESSAGES

         // If the First Strike misses, it can trigger Counterattack.
         if ( !ExecuteAttack( pFirst, pSecond, RollDiceWild(pSecond, pSecond->Fighting), 0, false, false, true, false ) )
         {
            if ( !pSecond->bShaken )
               ExecuteCounterattack( pFirst, pSecond );
         }

         if ( !pFirst->bDead && !pSecond->bDead )
         {
            int FirstRoll = RollDiceWild(pFirst, pFirst->Agility);
            int SecondRoll = RollDiceWild(pSecond, pSecond->Agility);
            bool bSuccess = (FirstRoll > SecondRoll);
#ifdef SHOW_MESSAGES
            std::cout << pFirst->Name << " tries to interrupt " << pSecond->Name << "..." << std::endl;
            std::string Result = "Agility roll of " + GetString(FirstRoll);
            Result += " opposed by " + GetString(SecondRoll);
            Result += bSuccess ? " = SUCCESS" : " = FAILURE";
            std::cout << Result << std::endl;
#endif // SHOW_MESSAGES

            if ( !bSuccess )
            {
               character_t *pTemp = pFirst;
               pFirst = pSecond;
               pSecond = pTemp;

               int Temp = FirstMax;
               FirstMax = SecondMax;
               SecondMax = Temp;
            }
         }
      }

      // Calculate the Gang Up bonus, if any.
      for ( int i = 0; i < FirstMax; ++i )
      {
         if ( FirstGangUp < 4 )
            FirstGangUp += !pFirst[i].bDead;
      }

      // The first character/s launch attacks.
      for ( int i = 0; i < FirstMax; ++i )
      {
         if ( !pFirst[i].bDead )
         {
            character_t *pTarget = NULL;
            for ( int j = 0; j < SecondMax; ++j )
            {
               if ( !pSecond[j].bDead )
               {
                  pTarget = &pSecond[j];
                  break;
               }
            }

            pFirst[i].GangUp = FirstGangUp;
            if ( pTarget != NULL )
               PerformAction(&pFirst[i], pTarget, bAdjacent);
         }
      }

      // Calculate the Gang Up bonus, if any.
      for ( int i = 0; i < SecondMax; ++i )
      {
         if ( SecondGangUp < 4 )
            SecondGangUp += !pSecond[i].bDead;
      }

      // The second character/s launch attacks.
      for ( int i = 0; i < SecondMax; ++i )
      {
         if ( !pSecond[i].bDead )
         {
            character_t *pTarget = NULL;
            for ( int j = 0; j < FirstMax; ++j )
            {
               if ( !pFirst[j].bDead )
               {
                  pTarget = &pFirst[j];
                  break;
               }
            }

            pSecond[i].GangUp = SecondGangUp;
            if ( pTarget != NULL )
               PerformAction(&pSecond[i], pTarget, bAdjacent);
         }
      }

      // Check if any of the player1 instances are still alive.
      bPlayer1Alive = false;
      for ( int i = 0; i < PLAYER1_COUNT; ++i )
      {
         Player1[i].bHasCounterattacked = false;
         if ( !Player1[i].bDead )
            bPlayer1Alive = true;
      }

      // Check if any of the player2 instances are still alive.
      bPlayer2Alive = false;
      for ( int i = 0; i < PLAYER2_COUNT; ++i )
      {
         Player2[i].bHasCounterattacked = false;
         if ( !Player2[i].bDead )
            bPlayer2Alive = true;
      }
   }

#ifdef SHOW_MESSAGES
   if ( bPlayer1Alive )
      std::cout << "\n>>> VICTORY: " << PLAYER1_NAME << " has defeated " << PLAYER2_NAME << "." << std::endl;
   else // bPlayer2Alive
      std::cout << "\n>>> VICTORY: " << PLAYER2_NAME << " has defeated " << PLAYER1_NAME << "." << std::endl;
#endif // SHOW_MESSAGES

   aRounds = Round;
   return bPlayer1Alive ? 1 : 2;
}

int main()
{
   srand ( time(NULL) );

   int Wins[2] = {0,0};
   int Rounds = 0;
   int Longest = -1, Shortest = -1;
   for ( int i = 0; i < NUMBER_OF_FIGHTS; ++i )
   {
#ifdef SHOW_MESSAGES
      if ( i > 0 )
         std::cout << std::endl;
      if ( NUMBER_OF_FIGHTS > 1 )
         std::cout << "---------------------------------\nFIGHT " << GetString(i+1) << "\n---------------------------------" << std::endl;
#endif // SHOW_MESSAGES

      int Round = 0;
      if ( GameLoop(Round) == 1 )
         ++Wins[0];
      else // Player 2 won.
         ++Wins[1];
      Rounds += Round;

      if ( i == 0 )
         Longest = Shortest = Round;
      else if ( Round < Shortest )
         Shortest = Round;
      else if ( Round > Longest )
         Longest = Round;
   }

#ifdef SHOW_MESSAGES
   if ( NUMBER_OF_FIGHTS > 1 )
      std::cout << "---------------------------------" << std::endl;
#endif // SHOW_MESSAGES

   if ( NUMBER_OF_FIGHTS > 1 )
   {
#ifdef SHOW_MESSAGES
      std::cout << "\n---------------------------------\n>>> OUTCOME:" << std::endl;
#endif // SHOW_MESSAGES
      std::cout << "There were " << GetString(NUMBER_OF_FIGHTS) << " fights.  " << PLAYER1_NAME << " won " << GetString(Wins[0]) << " of them, while " << PLAYER2_NAME << " won " << GetString(Wins[1]) << "." << std::endl;

      std::cout << "The shortest fight lasted " << GetString(Shortest) << " round";
      if ( Shortest > 1 ) std::cout << "s";
      std::cout << ", while the longest lasted " << GetString(Longest) << " round";
      if ( Longest > 1) std::cout << "s";
      std::cout << "." << std::endl;
      std::cout << "The average duration of a fight was " << GetString(Rounds/NUMBER_OF_FIGHTS) << " rounds." << std::endl;
   }

   return 0;
}
