Beispiel #1
0
 public Zone(Game game, Controller controller, Zone type)
 {
     Game       = game;
     Controller = controller;
     Type       = type;
     Game.Log(LogLevel.VERBOSE, BlockType.PLAY, "Zone", $"Created Zone {type} in Game with Controller {controller.Name}");
 }
Beispiel #2
0
        public virtual bool IsValidPlayTarget(ICharacter target = null)
        {
            // check if the current target is legit
            if (NeedsTargetList && target == null && ValidPlayTargets.Any())
            {
                Game.Log(LogLevel.VERBOSE, BlockType.PLAY, "Targeting", $"{this} hasn't a target and there are valid targets for this card.");
                return(false);
            }

            // target reqiuired for this card
            if (Card.RequiresTarget && target == null)
            {
                Game.Log(LogLevel.VERBOSE, BlockType.PLAY, "Targeting", $"{this} requires a target.");
                return(false);
            }

            // got target but isn't contained in valid targets
            if (target != null && !ValidPlayTargets.Contains(target))
            {
                Game.Log(LogLevel.VERBOSE, BlockType.PLAY, "Targeting", $"{this} has an invalid target {target}.");
                return(false);
            }

            return(true);
        }
Beispiel #3
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", !Game.Logging? "":$"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();
        }
Beispiel #4
0
        public TaskState Process()
        {
            CurrentTask = TaskList.OrderBy(p => p.Source.OrderOfPlay).First();
            TaskList.Remove(CurrentTask);
            Game.Log(LogLevel.VERBOSE, BlockType.TRIGGER, "TaskQueue", !Game.Logging? "":$"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);
        }
Beispiel #5
0
        public IPlayable Add(IPlayable entity, int zonePosition = -1)
        {
            if (zonePosition > _entitiesAsList.Count)
            {
                throw new ZoneException("Zoneposition '" + zonePosition + "' isn't in a valid range.");
            }

            // reset the card if it gets into the graveyard ...
            if (Type == Zone.GRAVEYARD)
            {
                entity.Reset();
            }

            MoveTo(entity, zonePosition < 0 ? _entitiesAsList.Count : zonePosition);
            Game.Log(LogLevel.DEBUG, BlockType.PLAY, "Zone", $"Entity '{entity} ({entity.Card.Type})' has been added to zone '{Type}' in position '{entity.ZonePosition}'.");

            // activate all zone changing enchantments
            entity.ApplyEnchantments(EnchantmentActivation.SETASIDE, Zone.SETASIDE);
            entity.ApplyEnchantments(EnchantmentActivation.BOARD, Zone.PLAY);
            entity.ApplyEnchantments(EnchantmentActivation.HAND, Zone.HAND);
            entity.ApplyEnchantments(EnchantmentActivation.DECK, Zone.DECK);

            entity.SetOrderOfPlay(Type.ToString());
            return(entity);
        }
Beispiel #6
0
        public bool TakeDamage(IPlayable source, int damage)
        {
            var hero   = this as Hero;
            var minion = this as Minion;

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

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

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

            if (minion != null && minion.IsImmune || hero != null && hero.IsImmune)
            {
                Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", $"{this} is immune.");
                return(false);
            }

            // remove armor first from hero ....
            if (hero != null && hero.Armor > 0)
            {
                if (hero.Armor < damage)
                {
                    damage     = damage - hero.Armor;
                    hero.Armor = 0;
                }
                else
                {
                    hero.Armor = hero.Armor - damage;
                    damage     = 0;
                }
            }

            // added pre damage to be able to interact
            PreDamage = damage;

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

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

            // check if there was damage done
            var tookDamage = PreDamage > 0;

            // reset predamage
            PreDamage = 0;

            return(tookDamage);
        }
Beispiel #7
0
        public void TakeHeal(IPlayable source, int heal)
        {
            // we don't heal undamaged entities
            if (Damage == 0)
            {
                return;
            }

            var amount = Damage > heal ? heal : Damage;

            Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", $"{this} took healing for {amount}.");
            Damage -= amount;
        }
Beispiel #8
0
        public void Shuffle(int times = 100)
        {
            // no need to shuffle something that has no or only one entity ...
            if (Count < 2)
            {
                return;
            }

            Game.Log(LogLevel.INFO, BlockType.PLAY, "Deck", $"Deck[{Game.FormatType}] from {Controller.Name} shuffling ({times}x).");
            for (var i = 0; i < times; i++)
            {
                Swap(Random, Random);
            }
        }
Beispiel #9
0
        public void RemoveWeapon()
        {
            if (Weapon == null)
            {
                return;
            }

            if (Weapon.HasDeathrattle)
            {
                Weapon.ApplyEnchantments(EnchantmentActivation.DEATHRATTLE, Enums.Zone.GRAVEYARD);
            }
            Game.Log(LogLevel.INFO, BlockType.PLAY, "Hero", $"Butcher's knife incoming to graveyard, say 'gugus' to {Weapon}");
            Controller.Graveyard.Add(Weapon);
            Weapon         = null;
            EquippedWeapon = 0;
        }
Beispiel #10
0
        public void Silence()
        {
            HasTaunt        = false;
            IsFrozen        = false;
            IsEnraged       = false;
            HasCharge       = false;
            HasWindfury     = false;
            HasDivineShield = false;
            HasStealth      = false;
            HasDeathrattle  = false;
            HasBattleCry    = false;
            HasInspire      = false;

            IsSilenced = true;

            Game.Log(LogLevel.INFO, BlockType.PLAY, "Minion", $"{this} got silenced!");
        }
Beispiel #11
0
        public void Fill()
        {
            var cards      = Game.FormatType == FormatType.FT_STANDARD ? Controller.Standard : Controller.Wild;
            var cardsToAdd = StartingCards - Count;

            Game.Log(LogLevel.INFO, BlockType.PLAY, "Deck", $"Deck[{Game.FormatType}] from {Controller.Name} filling up with {cardsToAdd} random cards.");
            while (cardsToAdd > 0)
            {
                var card = Util <Card> .Choose(cards);

                if (this.Count(c => c.Card == card) >= card.MaxAllowedInDeck)
                {
                    continue;
                }
                Entity.FromCard(Controller, card, null, this);
                cardsToAdd--;
            }
        }
Beispiel #12
0
        public int this[GameTag t]
        {
            get
            {
                //if (Card.Name.Equals("Angry Chicken"))
                //Game?.Log(LogLevel.DEBUG, BlockType.TRIGGER, "Entity", $"{this} get org. data {t} = {_data[t]}");

                var value = _data[t];

                // cumulative enchanment calculation ... priorizing game, zone, entity
                Game?.Enchants.ForEach(p => value = p.Apply(this, t, value));
                Zone?.Enchants.ForEach(p => value = p.Apply(this, t, value));
                Enchants.ForEach(p => value       = p.Apply(this, t, value));

                return(value);
            }
            set
            {
                var oldValue = _data[t];
                Game.Log(LogLevel.DEBUG, BlockType.TRIGGER, "Entity", $"{this} set data {t} to {value} oldvalue {oldValue}");
                //if (oldValue == value && t != GameTag.ZONE_POSITION)
                //{
                //    Game.Log(LogLevel.DEBUG, BlockType.TRIGGER, "Entity", $"{this} set data {t} to {value} obsolet as value is already that value.");
                //    return;
                //}

                SetNativeGameTag(t, value);

                Game.OnEntityChanged(this, t, oldValue, value);


                // don't trigger on explicit turned off heals or predamage changes ....
                if ((t == GameTag.DAMAGE || t == GameTag.PREDAMAGE) && IsIgnoreDamage)
                {
                    return;
                }

                // trigger here
                Game?.Triggers.ForEach(p => p.Change(this, t, oldValue, value));
                Zone?.Triggers.ForEach(p => p.Change(this, t, oldValue, value));
                Triggers.ForEach(p => p.Change(this, t, oldValue, value));
            }
        }
Beispiel #13
0
        public virtual bool IsValidAttackTarget(ICharacter target)
        {
            // got target but isn't contained in valid targets
            if (!ValidAttackTargets.Contains(target))
            {
                Game.Log(LogLevel.WARNING, BlockType.ACTION, "Character", $"{this} has an invalid target {target}.");
                return(false);
            }

            var hero = target as Hero;

            if (CantAttackHeroes && (hero != null))
            {
                Game.Log(LogLevel.WARNING, BlockType.ACTION, "Character", $"Can't attack Heroes!");
                return(false);
            }

            return(true);
        }
Beispiel #14
0
 public Controller(Game game, string name, int playerId, int id)
     : base(game, Card.CardPlayer,
            new Dictionary <GameTag, int>
 {
     //[GameTag.HERO_ENTITY] = heroId,
     [GameTag.MAXHANDSIZE]   = 10,
     [GameTag.STARTHANDSIZE] = 4,
     [GameTag.PLAYER_ID]     = playerId,
     [GameTag.TEAM_ID]       = playerId,
     [GameTag.ZONE]          = (int)Enums.Zone.PLAY,
     [GameTag.CONTROLLER]    = playerId,
     [GameTag.ENTITY_ID]     = id,
     [GameTag.MAXRESOURCES]  = 10,
     [GameTag.CARDTYPE]      = (int)CardType.PLAYER
 })
 {
     Name  = name;
     Zones = new Zones(game, this);
     Game.Log(LogLevel.INFO, BlockType.PLAY, "Controller", $"Created Controller '{name}'");
 }
Beispiel #15
0
        /// <summary>Invokes the method which corresponds to the next simulation step.</summary>
        /// <param name="game">The game subject.</param>
        /// <param name="step">The (next) step value.</param>
        /// <exception cref="ArgumentOutOfRangeException">step - when the provided step is unknown</exception>
        public void NextStepEvent(Game game, Step step)
        {
            game.Log(LogLevel.DEBUG, BlockType.TRIGGER, "Event", !game.Logging? "":$"NextStepEvent - {step}");
            switch (step)
            {
            case Step.BEGIN_FIRST:
                game.Step = step;
                game.BeginFirst();
                break;

            case Step.BEGIN_SHUFFLE:
                game.Step = step;
                game.BeginShuffle();
                break;

            case Step.BEGIN_DRAW:
                game.Step = step;
                game.BeginDraw();
                break;

            case Step.BEGIN_MULLIGAN:
                game.Step = step;
                game.BeginMulligan();
                break;

            case Step.MAIN_BEGIN:
                game.Step = step;
                game.MainBegin();
                break;

            case Step.MAIN_DRAW:
                game.Step = step;
                game.MainDraw();
                break;

            case Step.MAIN_READY:
                game.Step = step;
                game.MainReady();
                break;

            case Step.MAIN_RESOURCE:
                game.Step = step;
                game.MainRessources();
                break;

            case Step.MAIN_START:
                game.Step = step;
                game.MainStart();
                break;

            case Step.MAIN_START_TRIGGERS:
                game.Step = step;
                game.MainStartTriggers();
                break;

            case Step.MAIN_ACTION:
                game.Step = step;
                break;

            case Step.MAIN_COMBAT:
                break;

            case Step.MAIN_CLEANUP:
                game.Step = step;
                game.MainCleanUp();
                break;

            case Step.MAIN_END:
                game.Step = step;
                game.MainEnd();
                break;

            case Step.MAIN_NEXT:
                game.Step = step;
                game.MainNext();
                break;

            case Step.FINAL_WRAPUP:
                game.FinalWrapUp();
                break;

            case Step.FINAL_GAMEOVER:
                game.FinalGameOver();
                break;

            case Step.INVALID:
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(step), step, null);
            }
        }
Beispiel #16
0
 public Hero(Controller controller, Card card, Dictionary <GameTag, int> tags)
     : base(controller, card, tags)
 {
     Game.Log(LogLevel.VERBOSE, BlockType.PLAY, "Hero", $"{card.Name} ({card.Class}) was created.");
 }
Beispiel #17
0
 public Weapon(Controller controller, Card card, Dictionary <GameTag, int> tags)
     : base(controller, card, tags)
 {
     Game.Log(LogLevel.INFO, BlockType.PLAY, "Weapon", $"{this} ({Card.Class}) was created.");
 }
Beispiel #18
0
 public void GainArmor(IPlayable source, int armor)
 {
     Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", $"{this} gaining armor for {armor}.");
     Armor += armor;
 }
Beispiel #19
0
 public IPlayable Destroy()
 {
     ToBeDestroyed = true;
     Game.Log(LogLevel.VERBOSE, BlockType.PLAY, "Playable", $"{this} just got set to be destroyed.");
     return(this);
 }
Beispiel #20
0
        public virtual bool TargetingRequirements(ICharacter target)
        {
            var minion = target as Minion;

            if (minion != null && minion.HasStealth && minion.Controller != Controller)
            {
                return(false);
            }

            foreach (var item in Card.Requirements)
            {
                var req   = item.Key;
                var param = item.Value;

                Game.Log(LogLevel.DEBUG, BlockType.PLAY, "Targeting", $"{this} check PlayReq {req} for target {target.Card.Name} ... !");

                switch (req)
                {
                //[22] REQ_TARGET_IF_AVAILABLE - If one is available, target is required. [Always:False, Param:False]

                case PlayReq.REQ_MINION_TARGET:     // Target must be a minion.
                    if (!(target is Minion))
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_FRIENDLY_TARGET:     // Target must be friendly.
                    if (target.Controller != Controller)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_ENEMY_TARGET:     // Target must be an enemy.
                    if (target.Controller == Controller)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_DAMAGED_TARGET:     // Target must be damaged.
                    if (target.Damage == 0)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_FROZEN_TARGET:     // Target must be frozen.
                    if (!target.IsFrozen)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_CHARGE_TARGET:     // Target must have charge.
                    if (minion != null && minion.HasCharge)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_NONSELF_TARGET:     // Cannot target self.
                    if (this == target)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_TARGET_WITH_RACE:     // Target must have race: [Always:False, Param:True]
                    if (target.Race != (Race)param)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_HERO_TARGET:     // Target must be a hero.
                    if (!(target is Hero))
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_MUST_TARGET_TAUNTER:     // Must ALWAYS target taunters.
                    if (minion == null || !minion.HasTaunt)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_UNDAMAGED_TARGET:
                    if (target.Damage > 0)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_LEGENDARY_TARGET:
                    if (target.Card.Rarity != Rarity.LEGENDARY)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_TARGET_WITH_DEATHRATTLE:
                    if (minion == null || !minion.HasDeathrattle)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_TARGET_WITH_BATTLECRY:
                    if (minion == null || !minion.HasBattleCry)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_HERO_OR_MINION_TARGET:     // Target must be a hero or minion.
                    if (!(target is Minion) && !(target is Hero))
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_MINION_OR_ENEMY_HERO:
                    if (!(target is Minion) && target != Controller.Opponent.Hero)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_TARGET_MAX_ATTACK:     // Target must have a max atk of: [Always:False, Param:True]
                    if (target.AttackDamage > param)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_TARGET_MIN_ATTACK:     // Target must have a minimum atk of: [Always:False, Param:True]
                    if (target.AttackDamage < param)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_TARGET_IF_AVAILABLE_AND_MINIMUM_FRIENDLY_MINIONS:
                    if (Controller.Board.Count < param)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_TARGET_IF_AVAILABLE_AND_MINIMUM_FRIENDLY_SECRETS:
                    if (Controller.Secrets.Count < param)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_TARGET_IF_AVAILABLE_AND_DRAGON_IN_HAND:
                    if (!Controller.DragonInHand)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_STEALTHED_TARGET:
                    if (!(target is Minion) || !((Minion)target).HasStealth)
                    {
                        return(false);
                    }
                    break;

                case PlayReq.REQ_TARGET_FOR_COMBO:
                    if (!Controller.IsComboActive)
                    {
                        return(false);
                    }
                    break;

                // implemented in playable ...
                case PlayReq.REQ_NUM_MINION_SLOTS:
                case PlayReq.REQ_FRIENDLY_MINION_DIED_THIS_GAME:
                    break;

                // already implemented ... card.RequiresTarget and RequiresTargetIfAvailable
                case PlayReq.REQ_TARGET_TO_PLAY:
                case PlayReq.REQ_TARGET_IF_AVAILABLE:
                    break;

                // TODO still haven't implemented all playerreq ...
                case PlayReq.REQ_NONSTEALTH_ENEMY_TARGET:   // Enemy target cannot be stealthed.
                case PlayReq.REQ_MAX_SECRETS:
                case PlayReq.REQ_TARGET_ATTACKED_THIS_TURN: // Target must have already attacked this turn.
                case PlayReq.REQ_TARGET_TAUNTER:            // Default attack power must target taunters
                case PlayReq.REQ_CAN_BE_ATTACKED:           // Target cannot have the tag 'can't be attacked.'
                case PlayReq.REQ_TARGET_MAGNET:             // Must target magnet (enemy) minion if one exists.
                case PlayReq.REQ_CAN_BE_TARGETED_BY_SPELLS: // Can be targeted by spells.
                case PlayReq.REQ_CAN_BE_TARGETED_BY_OPPONENTS:
                // Target cannot have the tag 'can't be targeted by opponents.'
                case PlayReq.REQ_CAN_BE_TARGETED_BY_HERO_POWERS:
                // Target cannot have the tag 'can't be targeted by hero powers.'
                case PlayReq.REQ_ENEMY_TARGET_NOT_IMMUNE:     // Enemy target cannot be immune.
                case PlayReq.REQ_SUBCARD_IS_PLAYABLE:
                case PlayReq.REQ_CAN_BE_TARGETED_BY_BATTLECRIES:
                case PlayReq.REQ_FRIENDLY_MINION_DIED_THIS_TURN:
                case PlayReq.REQ_ENEMY_WEAPON_EQUIPPED:
                case PlayReq.REQ_SECRET_ZONE_CAP:
                case PlayReq.REQ_TARGET_EXACT_COST:
                case PlayReq.REQ_MINION_SLOT_OR_MANA_CRYSTAL_SLOT:
                    Game.Log(LogLevel.ERROR, BlockType.PLAY, "Targeting", $"PlayReq {req} not implemented right now!");
                    break;

                default:
                    Game.Log(LogLevel.ERROR, BlockType.PLAY, "Targeting", $"PlayReq {req} not in switch needs to be added!");
                    break;
                }
            }

            return(true);
        }