Beispiel #1
0
        public IEnumerator Dodge()
        {
            var dodgeComplete = false;

            _animator.DodgeCompleteSignal.AddOnce(() => {
                dodgeComplete = true;
            });
            State = CombatantState.Dodging;

            while (!dodgeComplete)
            {
                yield return(new WaitForEndOfFrame());
            }

            State = CombatantState.CombatReady;
        }
Beispiel #2
0
        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;
        }
Beispiel #3
0
        /// <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();
        }
Beispiel #4
0
        /// <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;
            }
        }
Beispiel #5
0
        /// <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();
        }
Beispiel #6
0
 public void ReturnToRest()
 {
     State = CombatantState.Idle;
 }
Beispiel #7
0
 public void PrepareForCombat(MathUtils.CardinalDirection direction)
 {
     Facing = direction;
     State  = CombatantState.CombatReady;
 }
Beispiel #8
0
        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();
        }
Beispiel #9
0
 public void AddAnimation(CombatantState state, Direction direction, Animation animation)
 {
     Animations[state].Add(direction, animation);
 }