private GameAction ProcessAttack(AttackResult attackerResult, FE7UnitEntity attacker, FE7UnitEntity defender) { int actualDamage = attackerResult.BaseDamage; if (attackerResult.Result != AttackRollResult.Miss) //hit or crit { // Calculate damage if (attacker.EquippedWeapon.IsMagic) { actualDamage -= defender.Resistance; if (actualDamage < 0) { actualDamage = 0; } } else { actualDamage -= defender.Defense; if (actualDamage < 0) { actualDamage = 0; } } if (attackerResult.Result == AttackRollResult.Crit) { actualDamage *= 3; return(new CombatCritAction(attacker, actualDamage, attackerResult.RandNumbersUsed)); } else { return(new CombatHitAction(attacker, actualDamage, attackerResult.RandNumbersUsed)); } } else { return(new CombatMissAction(attacker, attackerResult.RandNumbersUsed)); } }
List <GameAction> InitiateCombat(FE7UnitEntity attacker, FE7UnitEntity defender, int engagementRange) { List <GameAction> ret = new List <GameAction>(); if (!attacker.EquippedWeapon.Range.Contains(engagementRange)) { throw new WeaponException("Attack at improper range"); } bool defenderCanRetalliate = defender.EquippedWeapon.Range.Contains(engagementRange); int attackerAttackSpeed = attacker.AttackSpeed; int defenderAttackSpeed = defender.AttackSpeed; bool attackerDouble = attackerAttackSpeed - defenderAttackSpeed >= 4; bool defenderDouble = defenderAttackSpeed - attackerAttackSpeed >= 4; WeaponTriangle attackerWeapTriBonus = CalculateWeaponTriangle(attacker.EquippedWeapon.WeaponType, defender.EquippedWeapon.WeaponType); WeaponTriangle defenderWeapTriBonus = CalculateWeaponTriangle(defender.EquippedWeapon.WeaponType, attacker.EquippedWeapon.WeaponType); //[Precalculated -- Weapon Hit + (Skill x 2) + (Luck / 2) ]+ Support bonus + Weapon Triangle bonus + S Rank bonus + Tactician bonus int attackerHit = attacker.HitChance + 0 + ((int)attackerWeapTriBonus * 15) + 0 + 0; int defenderHit = defender.HitChance + 0 + ((int)defenderWeapTriBonus * 15) + 0 + 0; // [Precalculated -- (Attack Speed x 2) + Luck ]+ Support bonus + Terrain bonus + Tactician bonus defenderHit -= attacker.Avoid + 0 + CalcTerrainAvoidBonus(attacker.Terrain) + 0; attackerHit -= defender.Avoid + 0 + CalcTerrainAvoidBonus(defender.Terrain) + 0; // Weapon Critical + (Skill / 2) + Support bonus + Critical bonus + S Rank bonus - Crit Avoid [opponent's Luck + Support + Tactician Bonus] int attackerCrit = attacker.CritChance + 0 + 0 + 0 - defender.Luck - 0 - 0; int defenderCrit = defender.CritChance + 0 + 0 + 0 - attacker.Luck - 0 - 0; // StrengthMagic + Weapon Might + [ Weapon Triangle bonus x Effective coefficient] + Support bonus int attackerDamage = attacker.Might + ((int)attackerWeapTriBonus * 1) + 0 - CalcTerrainDefBonus(defender.Terrain); int defenderDamage = defender.Might + ((int)defenderWeapTriBonus * 1) + 0 - CalcTerrainDefBonus(attacker.Terrain); //attacker attacks first. GameAction attackerResult = ProcessAttack(MakeAttack(attackerHit, attackerCrit, attackerDamage), attacker, defender); ret.Add(attackerResult); //check to see if Defender is still alive. defender.TakeDamage(attackerResult); if (defender.HP > 0 && defenderCanRetalliate && defender.EquippedWeapon.WeaponType != FE7WeaponType.None) { //defender attacks GameAction defenderResult = ProcessAttack(MakeAttack(defenderHit, defenderCrit, defenderDamage), defender, attacker); ret.Add(defenderResult); attacker.TakeDamage(defenderResult); } //check to see if attacker is still alive if (attacker.HP > 0 && attackerDouble) { //attack again. GameAction followupResult = ProcessAttack(MakeAttack(attackerHit, attackerCrit, attackerDamage), attacker, defender); ret.Add(followupResult); //check to see if Defender is still alive. defender.TakeDamage(followupResult); } else if (defender.HP > 0 && defenderDouble && defender.EquippedWeapon.WeaponType != FE7WeaponType.None) { //defender attacks again. GameAction followupResult = ProcessAttack(MakeAttack(defenderHit, defenderCrit, defenderDamage), defender, attacker); ret.Add(followupResult); attacker.TakeDamage(followupResult); } //Now we check if either died. if (defender.HP > 0 && attacker.HP > 0) { //no one died. ret.Add(new CombatDrawAction(attacker, defender)); } else if (attacker.HP > 0) { //defender died ret.Add(new CombatDefenderDefeatAction(attacker, defender)); } else if (defender.HP > 0) { //attacker died ret.Add(new CombatAttackerDefeatAction(attacker, defender)); } else { //they both died. This shouldn't happen. Oops. throw new CombatEngineException("Both units dead after combat"); } return(ret); }