Ejemplo n.º 1
0
        public void Execute(ISimpleTask task, Controller controller, IPlayable source, IPlayable target)
        {
            ISimpleTask clone = task.Clone();

            clone.Game       = controller.Game;
            clone.Controller = controller;
            clone.Source     = source;
            clone.Target     = target;
            Game.Log(LogLevel.VERBOSE, BlockType.TRIGGER, "TaskQueue", $"PriorityTask[{clone.Source}]: '{clone.GetType().Name}' is processed!" +
                     $"'{clone.Source.Card.Text?.Replace("\n", " ")}'");

            // power block
            if (controller.Game.History)
            {
                controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.POWER, source.Id, "", -1, target?.Id ?? 0));
            }

            clone.Process();

            if (controller.Game.History)
            {
                controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
            }

            Game.TaskStack.Reset();
        }
Ejemplo n.º 2
0
        public override TaskState Process()
        {
            switch (Controller.Choice.ChoiceType)
            {
            case ChoiceType.MULLIGAN:
                Generic.ChoiceMulligan.Invoke(Controller, Choices);
                if (Controller.Game.History)
                {
                    Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, Controller.Id, "", 7, 0));
                }
                Controller.MulliganState = Enums.Mulligan.DONE;
                if (Controller.Game.History)
                {
                    Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
                }
                return(TaskState.COMPLETE);

            case ChoiceType.GENERAL:
                Generic.ChoicePick.Invoke(Controller, Choices[0]);
                Controller.Game.NextStep = Step.MAIN_CLEANUP;
                return(TaskState.COMPLETE);

            case ChoiceType.INVALID:
                throw new NotImplementedException();
            }
            return(TaskState.STOP);
        }
Ejemplo n.º 3
0
        public override TaskState Process()
        {
            switch (Controller.Choice.ChoiceType)
            {
            case ChoiceType.MULLIGAN:
                Generic.ChoiceMulligan.Invoke(Controller, Choices);
                if (Controller.Game.History)
                {
                    Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, Controller.Id, "", 7, 0));
                }
                Controller.MulliganState = Enums.Mulligan.DONE;
                if (Controller.Game.History)
                {
                    Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
                }
                return(TaskState.COMPLETE);

            case ChoiceType.GENERAL:
                if (!Generic.ChoicePick.Invoke(Controller, Choices[0]))
                {
                    return(TaskState.STOP);
                }
                Controller.NumOptionsPlayedThisTurn++;
                Game.ProcessTasks();
                Game.DeathProcessingAndAuraUpdate();
                return(TaskState.COMPLETE);

            case ChoiceType.INVALID:
                throw new NotImplementedException();
            }
            return(TaskState.STOP);
        }
Ejemplo n.º 4
0
        public TaskState Process()
        {
            ISimpleTask currentTask = CurrentQueue.Dequeue();

            CurrentTask = currentTask;

            //if (currentTask is StateTaskList tasks)
            //	tasks.Stack = new TaskStack(_game);

            _game.Log(LogLevel.VERBOSE, BlockType.TRIGGER, "TaskQueue", !_game.Logging ? "" : $"LazyTask[{currentTask.Source}]: '{currentTask.GetType().Name}' is processed!" +
                      $"'{currentTask.Source.Card.Text?.Replace("\n", " ")}'");
            if (_game.History)
            {
                _game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(currentTask.IsTrigger ? BlockType.TRIGGER : BlockType.POWER, currentTask.Source.Id, "", -1, currentTask.Target?.Id ?? 0));
            }

            TaskState success = currentTask.Process();

            if (_game.History)
            {
                _game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
            }

            // reset between task execution
            //_game.TaskStack.Reset();

            CurrentTask = null;

            return(success);
        }
Ejemplo n.º 5
0
        public TaskState Process()
        {
            CurrentTask = TaskList.OrderBy(p => p.Source.OrderOfPlay).First();
            TaskList.Remove(CurrentTask);
            Game.Log(LogLevel.VERBOSE, BlockType.TRIGGER, "TaskQueue", $"LazyTask[{CurrentTask.Source}]: '{CurrentTask.GetType().Name}' is processed!" +
                     $"'{CurrentTask.Source.Card.Text?.Replace("\n", " ")}'");


            // power block
            if (Game.History)
            {
                Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.POWER, CurrentTask.Source.Id, "", -1, CurrentTask.Target?.Id ?? 0));
            }

            TaskState success = CurrentTask.Process();

            if (Game.History)
            {
                Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
            }

            // reset between task execution
            Game.TaskStack.Reset();

            //if (Game.Splits.Count == 0 && CurrentTask.Splits != null && CurrentTask.Splits.Count > 0)
            //{
            //    Log.Info($"Parallel-threading splits '{CurrentTask.Splits.Count}' starting now! [Info: {Game.Splits.Count}]");
            //    Game.Splits = CurrentTask.Splits;
            //}
            return(success);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Part of the state machine.
        /// Runs when STATE = RUNNING &amp;&amp; NEXTSTEP = MAIN_READY
        /// </summary>
        public void MainReady()
        {
            if (History)
            {
                PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, CurrentPlayer.Id, "", 1, 0));
            }

            Characters.ForEach(p =>
            {
                p.NumTurnsInPlay++;
                p.NumAttacksThisTurn = 0;
            });

            Heroes.ForEach(p =>
            {
                p.Controller.NumCardsDrawnThisTurn              = 0;
                p.Controller.NumCardsPlayedThisTurn             = 0;
                p.Controller.NumMinionsPlayedThisTurn           = 0;
                p.Controller.NumOptionsPlayedThisTurn           = 0;
                p.Controller.NumFriendlyMinionsThatDiedThisTurn = 0;
            });

            CurrentPlayer.Hero.IsExhausted       = false;
            CurrentPlayer.Hero.Power.IsExhausted = false;
            foreach (var e in CurrentPlayer.BoardZone)
            {
                e.IsSummoned  = false;
                e.IsExhausted = false;
            }

            // De-activate combo buff
            CurrentPlayer.IsComboActive = false;

            CurrentPlayer.NumMinionsPlayerKilledThisTurn         = 0;
            CurrentOpponent.NumMinionsPlayerKilledThisTurn       = 0;
            CurrentPlayer.NumFriendlyMinionsThatAttackedThisTurn = 0;
            NumMinionsKilledThisTurn = 0;
            CurrentPlayer.HeroPowerActivationsThisTurn = 0;

            CurrentPlayer.NumElementalsPlayedLastTurn = CurrentPlayer.NumElementalsPlayedThisTurn;
            CurrentPlayer.NumElementalsPlayedThisTurn = 0;

            if (History)
            {
                PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
            }

            // set next step
            NextStep = Step.MAIN_START_TRIGGERS;
        }
Ejemplo n.º 7
0
        public static IPlayable Draw(Controller c, int index)
        {
            IPlayable playable = c.DeckZone.Remove(index);

            c.Game.Log(LogLevel.INFO, BlockType.ACTION, "DrawPhase", !c.Game.Logging ? "" : $"{c.Name} draws {playable}");

            c.NumCardsDrawnThisTurn++;
            c.NumCardsDrawnThisGame++;
            c.LastCardDrawn = playable.Id;

            if (AddHandPhase.Invoke(c, playable))
            {
                // DrawTrigger vs TOPDECK ?? not sure which one is first

                Game game = c.Game;

                game.TaskQueue.StartEvent();
                game.TriggerManager.OnDrawTrigger(playable);
                game.ProcessTasks();
                game.TaskQueue.EndEvent();

                ISimpleTask task = playable.Power?.TopDeckTask;
                if (task != null)
                {
                    if (game.History)
                    {
                        // TODO: triggerkeyword: TOPDECK
                        game.PowerHistory.Add(
                            PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, playable.Id, "", 0, 0));
                    }

                    c.SetasideZone.Add(c.HandZone.Remove(playable));

                    game.Log(LogLevel.INFO, BlockType.TRIGGER, "TOPDECK",
                             !game.Logging ? "" : $"{playable}'s TOPDECK effect is activated.");

                    task.Process(game, c, playable, null);

                    if (game.History)
                    {
                        game.PowerHistory.Add(
                            PowerHistoryBuilder.BlockEnd());
                    }
                }
            }

            c.DeckZone.ResetPositions();

            return(playable);
        }
Ejemplo n.º 8
0
 public void AddWeapon(Weapon weapon)
 {
     RemoveWeapon();
     weapon.SetOrderOfPlay("WEAPON");
     Weapon = weapon;
     Weapon[GameTag.ZONE]          = (int)Enums.Zone.PLAY;
     Weapon[GameTag.ZONE_POSITION] = 0;
     if (Game.History)
     {
         Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.POWER, Weapon.Id, "", -1, 0));
         Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
     }
     EquippedWeapon = weapon.Id;
 }
Ejemplo n.º 9
0
        /// <summary>
        /// Part of the state machine.
        /// Runs when STATE = RUNNING &amp;&amp; NEXTSTEP = MAIN_DRAW
        /// </summary>
        public void MainDraw()
        {
            if (History)
            {
                PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, CurrentPlayer.Id, "", 0, 0));                 // turn start effect
            }
            //CurrentPlayer.NumCardsToDraw = 1;
            Generic.Draw(CurrentPlayer);

            if (History)
            {
                PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
            }

            // set next step
            NextStep = Step.MAIN_START;
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Part of the state machine.
        /// Runs when STATE = RUNNING &amp;&amp; NEXTSTEP = MAIN_START_TRIGGERS
        /// </summary>
        public void MainStartTriggers()
        {
            CurrentPlayer.TurnStart = true;
            DeathProcessingAndAuraUpdate();

            if (History)
            {
                PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, CurrentPlayer.Id, "", 8, 0));
            }

            if (History)
            {
                PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
            }

            // set next step
            NextStep = Step.MAIN_RESOURCE;
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Part of the state machine.
        /// Runs when STATE = RUNNING &amp;&amp; NEXTSTEP = MAIN_NEXT
        /// </summary>
        public void MainNext()
        {
            if (History)
            {
                PowerHistoryBuilder.BlockStart(Enums.BlockType.TRIGGER, this.Id, "", -1, 0);
            }

            CurrentPlayer.NumTurnsLeft   = 0;
            CurrentOpponent.NumTurnsLeft = 1;

            // After a player ends their turn (just before the next player's Start of
            // Turn Phase), un-Freeze all characters they control that are Frozen,
            // don't have summoning sickness (or do have Charge) and have not attacked
            // that turn.
            CurrentPlayer.BoardZone.GetAll.ForEach(p =>
            {
                var minion = p as Minion;
                if (minion != null && minion.IsFrozen && minion.NumAttacksThisTurn == 0 && (!minion.IsSummoned || minion.HasCharge))
                {
                    minion.IsFrozen = false;
                }
            });
            if (CurrentPlayer.Hero.IsFrozen && CurrentPlayer.Hero.NumAttacksThisTurn == 0)
            {
                CurrentPlayer.Hero.IsFrozen = false;
            }

            // set player for next turn ...
            CurrentPlayer = CurrentOpponent;

            // count next turn
            Turn++;

            Log(LogLevel.INFO, BlockType.PLAY, "Game", $"CurentPlayer {CurrentPlayer.Name}.");

            if (History)
            {
                PowerHistoryBuilder.BlockEnd();
            }

            // set next step
            NextStep = Step.MAIN_READY;
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Part of the state machine.
        /// Runs when STATE = RUNNING &amp;&amp; NEXTSTEP = MAIN_CLEANUP
        /// </summary>
        public void MainCleanUp()
        {
            if (History)
            {
                PowerHistoryBuilder.BlockStart(Enums.BlockType.TRIGGER, CurrentPlayer.Id, "", 5, 0);
            }

            DeathProcessingAndAuraUpdate();

            if (History)
            {
                PowerHistoryBuilder.BlockEnd();
            }

            // move forward if game isn't won by any player now!
            NextStep = _players.ToList().TrueForAll(p => p.PlayState == PlayState.PLAYING)
                                ? Step.MAIN_ACTION
                                : Step.FINAL_WRAPUP;
        }
Ejemplo n.º 13
0
        public override bool Process()
        {
            Choice choice = Controller.Choice;

            if (choice == null)
            {
                return(false);
            }

            switch (choice.ChoiceType)
            {
            case ChoiceType.MULLIGAN:
                Generic.ChoiceMulligan.Invoke(Controller, Choices);
                if (Controller.Game.History)
                {
                    Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, Controller.Id, "", 7, 0));
                }
                Controller.MulliganState = Enums.Mulligan.DONE;
                if (Controller.Game.History)
                {
                    Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
                }
                return(true);

            case ChoiceType.GENERAL:
                //Game.CurrentEventData =
                //	new EventMetaData(Game.IdEntityDic[choice.SourceId], Game.IdEntityDic[Choices[0]]);
                if (!Generic.ChoicePick.Invoke(Controller, Game, Choices[0]))
                {
                    return(false);
                }
                Controller.NumOptionsPlayedThisTurn++;
                Game.ProcessTasks();
                Game.DeathProcessingAndAuraUpdate();
                //Game.CurrentEventData = null;
                return(true);

            case ChoiceType.INVALID:
                throw new NotImplementedException();
            }
            return(false);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Part of the state machine.
        /// Runs when STATE = RUNNING &amp;&amp; NEXTSTEP = MAIN_END
        /// </summary>
        public void MainEnd()
        {
            Log(LogLevel.INFO, BlockType.PLAY, "Game", $"End turn proccessed by player {CurrentPlayer}");

            if (History)
            {
                PowerHistoryBuilder.BlockStart(Enums.BlockType.TRIGGER, CurrentPlayer.Id, "", 4, 0);
            }

            CurrentPlayer.TurnStart = false;
            DeathProcessingAndAuraUpdate();

            if (History)
            {
                PowerHistoryBuilder.BlockEnd();
            }

            // set next step
            NextStep = Step.MAIN_NEXT;
        }
Ejemplo n.º 15
0
        public override TaskState Process()
        {
            if (Game.History)
            {
                Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.JOUST, Source.Id, "", 0, 0));
            }
            IPlayable playable = Generic.JoustBlock.Invoke(Controller, _type);

            if (Game.History)
            {
                Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
            }
            if (playable != null)
            {
                // add joust card winner to stack
                Playables = new List <IPlayable> {
                    playable
                };

                SuccessJoustTask.Game       = Game;
                SuccessJoustTask.Controller = Controller;
                SuccessJoustTask.Source     = Source;
                SuccessJoustTask.Target     = Target;

                return(SuccessJoustTask.Process());
            }

            if (FailedJoustTask != null)
            {
                FailedJoustTask.Game       = Game;
                FailedJoustTask.Controller = Controller;
                FailedJoustTask.Source     = Source;
                FailedJoustTask.Target     = Target;

                return(FailedJoustTask.Process());
            }

            Game.OnRandomHappened(true);

            return(TaskState.COMPLETE);
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Part of the state machine.
        /// Runs when STATE = RUNNING &amp;&amp; NEXTSTEP = BEGIN_MULLIGAN
        /// </summary>
        public void BeginMulligan()
        {
            Log(LogLevel.VERBOSE, BlockType.PLAY, "Game", $"Begin Mulligan.");

            // starting mulligan draw block
            if (History)
            {
                PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, this.Id, "", -1, 0));
            }

            Player1.MulliganState = Mulligan.INPUT;
            Player2.MulliganState = Mulligan.INPUT;

            Generic.CreateChoice.Invoke(Player1, this, ChoiceType.MULLIGAN, ChoiceAction.HAND, Player1.HandZone.Select(p => p.Id).ToList());
            Generic.CreateChoice.Invoke(Player2, this, ChoiceType.MULLIGAN, ChoiceAction.HAND, Player2.HandZone.Select(p => p.Id).ToList());

            // ending mulligan draw block
            if (History)
            {
                PowerHistory.Add(PowerHistoryBuilder.BlockEnd());
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Move destroyed entities from <see cref="Zone.PLAY"/> <see cref="Zone{T}"/> into
        /// <see cref="Zone.GRAVEYARD"/>
        /// </summary>
        public void GraveYard()
        {
            // remove dead weapons
            var heroesBadWeapons =
                Heroes.Where(p => p.Weapon != null && (p.Weapon.Durability == 0 || p.Weapon.ToBeDestroyed)).ToList();

            heroesBadWeapons.ForEach(p => p.RemoveWeapon());

            // check for dead minions to carry to the graveyard
            Minions.Where(p => p.IsDead).ToList().ForEach(p =>
            {
                Log(LogLevel.INFO, BlockType.PLAY, "Game", $"{p} is Dead! Graveyard say 'Hello'!");
                p.Zone.Remove(p);
                if (p.HasDeathrattle)
                {
                    p.ApplyEnchantments(EnchantmentActivation.DEATHRATTLE, Enums.Zone.GRAVEYARD);
                }
                if (History)
                {
                    PowerHistoryBuilder.BlockStart(BlockType.DEATHS, 1, "", 0, 0);
                }
                p.IsExhausted = false;
                p.Controller.GraveyardZone.Add(p);
                p.Controller.NumFriendlyMinionsThatDiedThisTurn++;
                CurrentPlayer.NumMinionsPlayerKilledThisTurn++;
                NumMinionsKilledThisTurn++;
                p.Damage = 0;
                if (History)
                {
                    PowerHistoryBuilder.BlockEnd();
                }
            });

            // check for dead heroes
            var deadHeroes = Heroes.Where(p => p.IsDead).ToList();

            deadHeroes.ForEach(p => p.Controller.PlayState = deadHeroes.Count > 1 ? PlayState.TIED : PlayState.LOSING);
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Part of the state machine.
        /// Runs when STATE = RUNNING.
        /// </summary>
        public void StartGame()
        {
            Log(LogLevel.INFO, BlockType.PLAY, "Game", "Starting new game now!");

            // setting up the decks ...
            _gameConfig.Player1Deck?.ForEach(p => Entity.FromCard(Player1, p, null, Player1.DeckZone));
            _gameConfig.Player2Deck?.ForEach(p => Entity.FromCard(Player2, p, null, Player2.DeckZone));
            if (_gameConfig.FillDecks)
            {
                Player1.DeckZone.Fill();
                Player2.DeckZone.Fill();
            }

            // set gamestats
            State = State.RUNNING;
            _players.ToList().ForEach(p => p.PlayState = PlayState.PLAYING);

            // starting mulligan draw block
            if (History)
            {
                PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, this.Id, "", -1, 0));
            }

            // getting first player
            FirstPlayer = _gameConfig.StartPlayer < 0
                                ? _players[Util.Random.Next(0, 2)]
                                : _players[_gameConfig.StartPlayer - 1];
            CurrentPlayer = FirstPlayer;

            Log(LogLevel.INFO, BlockType.PLAY, "Game", $"Starting Player is {CurrentPlayer.Name}.");

            // first turn
            Turn = 1;

            // set next step
            NextStep = Step.BEGIN_FIRST;
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Part of the state machine.
        /// Runs when STATE = RUNNING &amp;&amp; NEXTSTEP = FINAL_WRAPUP
        /// </summary>
        public void FinalWrapUp()
        {
            if (History)
            {
                PowerHistoryBuilder.BlockStart(Enums.BlockType.TRIGGER, Id, "", -1, 0);
            }

            Heroes.ForEach(p =>
            {
                if (p.Controller.PlayState == PlayState.LOSING || p.Controller.PlayState == PlayState.CONCEDED)
                {
                    p.Controller.PlayState          = PlayState.LOST;
                    p.Controller.Opponent.PlayState = PlayState.WON;
                }
            });

            if (History)
            {
                PowerHistoryBuilder.BlockEnd();
            }

            // set next step
            NextStep = Step.FINAL_GAMEOVER;
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Inflict damage onto this character.
        /// The actual amount still needs to be determined by the current
        /// state of the game. eg: The presence of immunity effects can cause
        /// the damage to be ignored.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="damage"></param>
        /// <returns></returns>
        public int TakeDamage(IPlayable source, int damage)
        {
            var hero   = this as Hero;
            var minion = this as Minion;

            bool fatigue = hero != null && this == source;

            if (fatigue)
            {
                hero.Fatigue = damage;
            }

            if (minion != null && minion.HasDivineShield)
            {
                Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", !Game.Logging? "":$"{this} divine shield absorbed incoming damage.");
                minion.HasDivineShield = false;
                return(0);
            }

            int armor = hero?.Armor ?? 0;

            // added pre damage
            int preDamage = hero == null ? damage : armor < damage ? damage - armor : 0;

            PreDamage = preDamage;



            // Predamage triggers
            Game.TaskStack.SetDamageMetaData(source, this);
            PreDamageTrigger?.Invoke(this, preDamage);

            // reflect changes from tasks
            preDamage = PreDamage;
            if (this.IsImmune)
            {
                Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", !Game.Logging? "":$"{this} is immune.");
                PreDamage = 0;
                Trigger.Invalidate(Game, SequenceType.DamageDealt);
                return(0);
            }

            // remove armor first from hero ....
            if (armor > 0)
            {
                hero.Armor = armor < damage ? 0 : armor - damage;
            }


            // final damage is beeing accumulated
            Damage += preDamage;

            Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", !Game.Logging? "":$"{this} took damage for {PreDamage}({damage}). {(fatigue ? "(fatigue)" : "")}");

            // check if there was damage done
            int tookDamage = preDamage;

            // reset predamage
            PreDamage = 0;

            LastAffectedBy = source.Id;

            // Damage event is created
            // Collect all the tasks and sort them by order of play
            // Death phase and aura update is not emerge here

            // on-damage triggers
            Game.TaskQueue.StartEvent();
            Game.TriggerManager.OnDamageTrigger(this);
            Game.TriggerManager.OnDealDamageTrigger(source, preDamage);
            Game.ProcessTasks();
            Game.TaskQueue.EndEvent();
            if (source.HasLifeSteal && !_lifestealChecker)
            {
                if (_history)
                {
                    Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, source.Id, source.Card.Id, -1, 0));                     // TriggerKeyword=LIFESTEAL
                }
                Game.Log(LogLevel.VERBOSE, BlockType.ATTACK, "TakeDamage", !_logging ? "" : $"lifesteal source {source} has damaged target for {preDamage}.");
                source.Controller.Hero.TakeHeal(source, preDamage);
                if (_history)
                {
                    Game.PowerHistory.Add(new PowerHistoryBlockEnd());
                }

                if (source.Controller.Hero.ToBeDestroyed && source.Controller.Hero.Health > 0)
                {
                    source.Controller.Hero.ToBeDestroyed = false;
                }
            }

            return(tookDamage);
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Inflict damage onto this character.
        /// The actual amount still needs to be determined by the current
        /// state of the game. eg: The presence of immunity effects can cause
        /// the damage to be ignored.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="damage"></param>
        /// <returns></returns>
        public int TakeDamage(IPlayable source, int damage)
        {
            var hero   = this as Hero;
            var minion = this as Minion;

            if (minion != null && minion.Zone.Type != Enums.Zone.PLAY)
            {
                return(0);
            }

            bool fatigue = hero != null && this == source;

            if (fatigue)
            {
                hero.Fatigue = damage;
            }

            if (minion != null && minion.HasDivineShield)
            {
                Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", !Game.Logging? "":$"{this} divine shield absorbed incoming damage.");
                minion.HasDivineShield = false;
                return(0);
            }

            int armor = hero?.Armor ?? 0;

            int amount = hero == null ? damage : armor < damage ? damage - armor : 0;

            // added pre damage
            PreDamage = amount;

            // Predamage triggers (Ice Block)
            if (PreDamageTrigger != null)
            {
                PreDamageTrigger.Invoke(this);
                amount = PreDamage;
            }
            if (IsImmune)
            {
                Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", !Game.Logging ? "" : $"{this} is immune.");
                PreDamage = 0;
                return(0);
            }

            // remove armor first from hero ....
            if (armor > 0)
            {
                hero.Armor = armor < damage ? 0 : armor - damage;
            }

            // final damage is beeing accumulated
            Damage += amount;

            Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", !Game.Logging? "":$"{this} took damage for {PreDamage}({damage}). {(fatigue ? "(fatigue)" : "")}");

            // reset predamage
            PreDamage = 0;

            //LastAffectedBy = source.Id;	TODO


            // Damage event is created
            // Collect all the tasks and sort them by order of play
            // Death phase and aura update are not emerge here

            // place event related data
            Game.TaskQueue.StartEvent();
            EventMetaData temp = Game.CurrentEventData;

            Game.CurrentEventData = new EventMetaData(source, this, amount);

            // on-damage triggers
            TakeDamageTrigger?.Invoke(this);
            Game.TriggerManager.OnDamageTrigger(this);
            Game.TriggerManager.OnDealDamageTrigger(source);
            Game.ProcessTasks();
            Game.TaskQueue.EndEvent();
            Game.CurrentEventData = temp;

            if (source.HasLifeSteal && !_lifestealChecker)
            {
                if (_history)
                {
                    Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, source.Id, source.Card.Id, -1, 0));                     // TriggerKeyword=LIFESTEAL
                }
                Game.Log(LogLevel.VERBOSE, BlockType.ATTACK, "TakeDamage", !_logging ? "" : $"lifesteal source {source} has damaged target for {amount}.");
                source.Controller.Hero.TakeHeal(source, amount);
                if (_history)
                {
                    Game.PowerHistory.Add(new PowerHistoryBlockEnd());
                }

                if (source.Controller.Hero.ToBeDestroyed && source.Controller.Hero.Health > 0)
                {
                    source.Controller.Hero.ToBeDestroyed = false;
                }
            }

            if (this is Hero h)
            {
                h.IsDamagedThisTurn = true;
            }

            return(amount);
        }