public IEnumerator Dodge() { var dodgeComplete = false; _animator.DodgeCompleteSignal.AddOnce(() => { dodgeComplete = true; }); State = CombatantState.Dodging; while (!dodgeComplete) { yield return(new WaitForEndOfFrame()); } State = CombatantState.CombatReady; }
public IEnumerator Attack(ICombatant receiver, WeaponHitSeverity severity) { var attackComplete = false; var onComplete = new Action(() => { attackComplete = true; }); _animator.AttackConnectedSignal.AddOnce(() => { var connection = new WeaponHitConnection(severity, receiver); AttackConnectedSignal.Dispatch(connection); }); _animator.AttackCompleteSignal.AddOnce(onComplete); State = CombatantState.Attacking; while (!attackComplete) { yield return(new WaitForEndOfFrame()); } State = CombatantState.CombatReady; }
/// <summary> /// The main battle resolution /// Combatants must come from a lair in a hex. /// </summary> /// <param name="attackerLands"></param> /// <param name="defenderLands"></param> /// <param name="attackerBase"></param> /// <param name="defenderBase"></param> public void ResolveBattle(HexData attackerLands, HexData defenderLands, Lair attackerBase, Lair defenderBase) { if (attackerBase.IsRuins()) { // no attackers! do not pass! AttackerState = CombatantState.COMBATANT_STATE_ELIMINATED; return; } Civilization attacker = attackerBase.HomeCiv; string record; if (defenderBase.IsRuins()) { record = (defenderBase.GetFullName() + " is found abandoned by the " + attacker.GetPluralName()); defenderBase.History.addRecord(record); attacker.History.addRecord(record, isLogged: false); defenderBase.MoveCivIn(attacker); attackerBase.ForceAbandon(); defenderBase.Treasure += attackerBase.Treasure; attackerBase.Treasure = 0; DefenderState = CombatantState.COMBATANT_STATE_ELIMINATED; return; } Civilization defender = defenderBase.HomeCiv; // since this method is only called on initial spawn, then the // rule is to merge if two of the same race spawn in the same // hex area. if (attacker.Patricians.BaseAncestry.Name == defender.Patricians.BaseAncestry.Name) { defender.JoinOurCivilization(attacker.GetFullName()); defender.Patricians.Members += attacker.Patricians.Members; attacker.DissolvePopulation(); return; } record = "The " + attacker.GetPluralName() + " are attacking the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; attacker.History.addRecord(record); defender.History.addRecord(record, isLogged: false); defenderBase.History.addRecord(record, isLogged: false); GatherAttackers(attacker, attackerLands, defender.GetFullName()); GatherDefenders(defender, defenderLands, attacker.GetFullName()); _attackerStartingForces = GetTotalCombatants(AttackerList); _defenderStartingForces = GetTotalCombatants(DefenderList); _executeMainBattleLoop(); // recover from battle ResolveSurvivors(_attackerStartingForces, AttackerList); ResolveSurvivors(_defenderStartingForces, DefenderList); // determine outcome of battle. bool isAttackerLost = (AttackerState == CombatantState.COMBATANT_STATE_ELIMINATED) || (AttackerState == CombatantState.COMBATANT_STATE_ROUTED); bool isDefenderLost = (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED) || (DefenderState == CombatantState.COMBATANT_STATE_ROUTED); bool isBothLost = isAttackerLost && isDefenderLost; bool isMutualDestruction = (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED && AttackerState == CombatantState.COMBATANT_STATE_ELIMINATED); if (isMutualDestruction) { // mutual destruction is highly unlikely, but not impossible. record = "The " + attacker.GetPluralName() + " and the " + defender.GetPluralName() + " have achieved mutual destruction at " + defenderBase.GetFullName() + "!"; attacker.DissolvePopulation(); defender.DissolvePopulation(); } else if (isBothLost) { if (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED) { // defenders lose record = "The " + defender.GetPluralName() + " have been defeated by the " + attacker.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string defenderBaseName = defenderBase.Name; MoveLosers(defender, defenderLands, defenderBaseName); defenderBase.MoveCivIn(attacker); attackerBase.ForceAbandon(); defenderBase.Treasure += attackerBase.Treasure; attackerBase.Treasure = 0; } else { record = "The " + attacker.GetPluralName() + " have been repelled by the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string attackerBaseName = attackerBase.Name; // It's interesting that attackers don't go back home. MoveLosers(attacker, attackerLands, attackerBaseName); attackerBase.ForceAbandon(); } } else if (isDefenderLost) { // defender loses! record = "The " + defender.GetPluralName() + " have been defeated by the " + attacker.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string defenderBaseName = defenderBase.Name; MoveLosers(defender, defenderLands, defenderBaseName); defenderBase.MoveCivIn(attacker); attackerBase.ForceAbandon(); defenderBase.Treasure += attackerBase.Treasure; attackerBase.Treasure = 0; } else // attacker lost { // attacker loses! record = "The " + attacker.GetPluralName() + " have been repelled by the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string attackerBaseName = attackerBase.Name; // It's interesting that attackers don't go back home. MoveLosers(attacker, attackerLands, attackerBaseName); attackerBase.ForceAbandon(); } _recordBattleReport(record, attacker, defender, defenderBase); // any lingering civs with zero population are removed. _worldMap.CleanOutRuins(); }
/// <summary> /// Run a single round of combat /// </summary> public void ExecuteBattleRound(int numRounds) { // TODO: should these calculations be performaed by the population obj? int attackerForces = GetTotalCombatants(AttackerList); var attackerPop = AttackerList[0].Patricians; var attackerAncestry = attackerPop.BaseAncestry; int numAttackerUnits = AttackerList.Count; int attackerNumAttacks = (attackerAncestry.BaseNumAttacks * attackerForces) + attackerPop.BonusAttacks; int attackerHitBonus = attackerAncestry.BaseToHit + attackerPop.ToHitMod; int attackerAc = attackerAncestry.BaseAc + attackerPop.AcMod; int attackerHd = attackerAncestry.HitDice + attackerPop.HitDiceBonus; int attackerDamageTaken = 0; int defenderForces = GetTotalCombatants(DefenderList); var defenderPop = DefenderList[0].Patricians; var defenderAncestry = defenderPop.BaseAncestry; int numDefenderunits = DefenderList.Count; int defenderNumAttacks = defenderAncestry.BaseNumAttacks * defenderForces + defenderPop.BonusAttacks; int defenderHitBonus = defenderAncestry.BaseToHit + defenderPop.ToHitMod; int defenderAc = defenderAncestry.BaseAc + defenderPop.AcMod; int defenderHd = defenderAncestry.HitDice + defenderPop.HitDiceBonus; int defenderDamageTaken = 0; Console.WriteLine(attackerForces + " attackers vs " + defenderForces + " defenders"); // attacker attacks for (int i = 0; i < attackerNumAttacks; ++i) { int attackRoll = _dice.Roll(1, 20) + attackerHitBonus; if (attackRoll >= defenderAc) { ++defenderDamageTaken; } } int defenderCasualties = defenderDamageTaken / defenderHd; // defender counters for (int i = 0; i < defenderNumAttacks; ++i) { int attackRoll = _dice.Roll(1, 20) + defenderHitBonus; if (attackRoll >= attackerAc) { ++attackerDamageTaken; } } int attackerCasualties = attackerDamageTaken / attackerHd; Console.WriteLine("Attacker casualties: " + attackerCasualties + " | Defender casualties: " + defenderCasualties); // attackers take losses spread over units float attackerUnitLosses = attackerCasualties / numAttackerUnits; if (attackerUnitLosses > 0 && attackerUnitLosses < 1) { attackerUnitLosses = 1; } foreach (var attacker in AttackerList) { if (attacker.Patricians.Members <= attackerUnitLosses) { attacker.Patricians.Members = 0; } else { attacker.Patricians.Members -= (int)attackerUnitLosses; } } // defender takes losses spread over units float defenderUnitLosses = defenderCasualties / numDefenderunits; if (defenderUnitLosses > 0 && defenderUnitLosses < 1) { defenderUnitLosses = 1; } foreach (var defender in DefenderList) { if (defender.Patricians.Members <= defenderUnitLosses) { defender.Patricians.Members = 0; } else { defender.Patricians.Members -= (int)defenderUnitLosses; } } _attackerScore += defenderCasualties; _defenderScore += attackerCasualties; Console.WriteLine("Total score: Attacker - " + _attackerScore + " | Defender - " + _defenderScore + ". Current totals: Attacker - " + GetTotalCombatants(AttackerList) + " | Defender - " + GetTotalCombatants(DefenderList)); // determine loser and check morale... int moraleRoll = _dice.Roll(1, 20); int attackMoraleBonus = AttackerList[0].Patricians.MoraleBonus + AttackerList[0].Patricians.BaseAncestry.MoraleBonus; int defenseMoraleBonus = DefenderList[0].Patricians.MoraleBonus + DefenderList[0].Patricians.BaseAncestry.MoraleBonus; if (defenderCasualties < attackerCasualties) { Console.WriteLine("Attacker losing"); // attacker losing if (GetTotalCombatants(AttackerList) <= _attackerStartingForces / 3) { Console.WriteLine( "Attacker lost over 1/3 foces and routing."); AttackerState = CombatantState.COMBATANT_STATE_ROUTED; } else if ((moraleRoll + attackMoraleBonus) < 10) { Console.WriteLine("Attacker failed morale and routing."); AttackerState = CombatantState.COMBATANT_STATE_ROUTED; } } else if (attackerCasualties < defenderCasualties) { Console.WriteLine("Defender losing"); // defender losing if (GetTotalCombatants(DefenderList) <= _defenderStartingForces / 3) { Console.WriteLine( "Defender lost over 1/3 forces and routing."); DefenderState = CombatantState.COMBATANT_STATE_ROUTED; } else if ((moraleRoll + defenseMoraleBonus) < 10) { Console.WriteLine("Defender failed morale and routing."); DefenderState = CombatantState.COMBATANT_STATE_ROUTED; } } else if (numRounds > 10) { int defenseRoll = _dice.Roll(1, 20) + defenseMoraleBonus; int attackRoll = _dice.Roll(1, 20) + attackMoraleBonus; if (defenseRoll < attackRoll) { DefenderState = CombatantState.COMBATANT_STATE_ROUTED; Console.WriteLine("Defender routes from War Fatigue."); } else { AttackerState = CombatantState.COMBATANT_STATE_ROUTED; Console.WriteLine("Attacker routes form War Fatugue."); } } // else stalemate, no moaral checks until round 10 // Very unlikely, but check for genocide if (GetTotalCombatants(AttackerList) == 0) { Console.WriteLine("Attacker forces have been eliminated!"); AttackerState = CombatantState.COMBATANT_STATE_ELIMINATED; } if (GetTotalCombatants(DefenderList) == 0) { Console.WriteLine("Defender forces have been eliminated!"); DefenderState = CombatantState.COMBATANT_STATE_ELIMINATED; } }
/// <summary> /// Overloaded function for determining battles started by outside /// or homeless invaders. /// </summary> /// <param name="attacker"></param> /// <param name="defenderLands"></param> /// <param name="defenderBase"></param> public void ResolveBattle(Civilization attacker, HexData defenderLands, Lair defenderBase) { string record; if (defenderBase.IsRuins()) { record = (defenderBase.GetFullName() + " is found abandoned by the " + attacker.GetPluralName()); defenderBase.History.addRecord(record); attacker.History.addRecord(record, isLogged: false); defenderBase.MoveCivIn(attacker); defenderBase.Treasure += 1; DefenderState = CombatantState.COMBATANT_STATE_ELIMINATED; return; } Civilization defender = defenderBase.HomeCiv; record = "The " + attacker.GetPluralName() + " are attacking the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; attacker.History.addRecord(record); defender.History.addRecord(record, isLogged: false); defenderBase.History.addRecord(record, isLogged: false); AttackerList.Add(attacker); GatherDefenders(defender, defenderLands, attacker.GetFullName()); _attackerStartingForces = GetTotalCombatants(AttackerList); _defenderStartingForces = GetTotalCombatants(DefenderList); _executeMainBattleLoop(); // recover from battle ResolveSurvivors(_attackerStartingForces, AttackerList); ResolveSurvivors(_defenderStartingForces, DefenderList); // determine outcome of battle. bool isAttackerLost = (AttackerState == CombatantState.COMBATANT_STATE_ELIMINATED) || (AttackerState == CombatantState.COMBATANT_STATE_ROUTED); bool isDefenderLost = (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED) || (DefenderState == CombatantState.COMBATANT_STATE_ROUTED); bool isBothLost = isAttackerLost && isDefenderLost; bool isMutualDestruction = (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED && AttackerState == CombatantState.COMBATANT_STATE_ELIMINATED); if (isMutualDestruction) { // mutual destruction is highly unlikely, but not impossible. record = "The " + attacker.GetPluralName() + " and the " + defender.GetPluralName() + " have achieved mutual destruction at " + defenderBase.GetFullName() + "!"; attacker.DissolvePopulation(); defender.DissolvePopulation(); } else if (isBothLost) { if (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED) { // defender loses! record = "The " + defender.GetPluralName() + " have been defeated by the " + attacker.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string defenderBaseName = defenderBase.Name; MoveLosers(defender, defenderLands, defenderBaseName); defenderBase.MoveCivIn(attacker); defenderBase.Treasure += 1; } else { // attacker loses! record = "The " + attacker.GetPluralName() + " have been repelled by the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; // In this case, the attackers seek to allign themselves // possibly where they landed. MoveLosers(attacker, defenderLands, baseName: ""); } } else if (isDefenderLost) { // defender loses! record = "The " + defender.GetPluralName() + " have been defeated by the " + attacker.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string defenderBaseName = defenderBase.Name; MoveLosers(defender, defenderLands, defenderBaseName); defenderBase.MoveCivIn(attacker); defenderBase.Treasure += 1; } else // attacker lost { // attacker loses! record = "The " + attacker.GetPluralName() + " have been repelled by the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; // In this case, the attackers seek to allign themselves // possibly where they landed. MoveLosers(attacker, defenderLands, baseName: ""); } _recordBattleReport(record, attacker, defender, defenderBase); // any lingering civs with zero population are removed. _worldMap.CleanOutRuins(); }
public void ReturnToRest() { State = CombatantState.Idle; }
public void PrepareForCombat(MathUtils.CardinalDirection direction) { Facing = direction; State = CombatantState.CombatReady; }
public BaseCombatant(Personnage basePersonnage) : base() { State = DEFAULT_STATE; CellPosition = new Vector2I(); Direction = GameData.DEFAULT_DIRECTION; Animations = new Dictionary<CombatantState, Dictionary<Direction, Animation>>(); foreach (CombatantState combatantState in System.Enum.GetValues(typeof(CombatantState))) Animations.Add(combatantState, new Dictionary<Direction, Animation>()); AddAnimation(CombatantState.Normal, Direction.N, new Animation((Animation)basePersonnage.GetSkin("Inactive", Direction.N))); AddAnimation(CombatantState.Normal, Direction.E, new Animation((Animation)basePersonnage.GetSkin("Inactive", Direction.E))); AddAnimation(CombatantState.Normal, Direction.S, new Animation((Animation)basePersonnage.GetSkin("Inactive", Direction.S))); AddAnimation(CombatantState.Normal, Direction.O, new Animation((Animation)basePersonnage.GetSkin("Inactive", Direction.O))); AddAnimation(CombatantState.Moving, Direction.N, new Animation((Animation)basePersonnage.GetSkin("Moving", Direction.N))); AddAnimation(CombatantState.Moving, Direction.E, new Animation((Animation)basePersonnage.GetSkin("Moving", Direction.E))); AddAnimation(CombatantState.Moving, Direction.S, new Animation((Animation)basePersonnage.GetSkin("Moving", Direction.S))); AddAnimation(CombatantState.Moving, Direction.O, new Animation((Animation)basePersonnage.GetSkin("Moving", Direction.O))); foreach (CombatantState state in Animations.Keys) foreach (Animation animation in Animations[state].Values) animation.Play(); MoveInfo = new CMoveInfo(this); Status = new CombatantStatus(); Status.OnChange += new StatusChangeEventHandler(Status_OnChange); SpellPanoply = new SpellPanoply(); }
public void AddAnimation(CombatantState state, Direction direction, Animation animation) { Animations[state].Add(direction, animation); }