Пример #1
0
        public override OrderedDictionary Vector()
        {
            OrderedDictionary v = base.Vector();

            //if (Auras.Count > 0)
            for (int i = 0; i < Auras.Count; ++i)
            {
                v.AddRange(Auras[i].Vector(), Prefix());
            }

            //else
            //	v.AddRange(Aura.NullVector, Prefix);

            v.Add($"{Prefix()}DamageTakenThisTurn", DamageTakenThisTurn);
            v.Add($"{Prefix()}EquippedWeapon", EquippedWeapon != 0 ? Controller.Game.IdEntityDic[EquippedWeapon].Card.AssetId : 0);
            v.Add($"{Prefix()}ExtraAttacksThisTurn", ExtraAttacksThisTurn);
            v.Add($"{Prefix()}Fatigue", Fatigue);
            v.AddRange(HeroPower.Vector(), Prefix());
            v.Add($"{Prefix()}HeroPowerDamage", HeroPowerDamage);
            if (Weapon != null)
            {
                v.AddRange(Weapon.Vector(), Prefix());
            }
            //v.AddRange(Weapon != null ? Weapon.Vector : Weapon.NullVector, Prefix);

            return(v);
        }
Пример #2
0
 private HeroPower GetHeroPower(SabberStoneCore.Model.Entities.HeroPower heroPower)
 {
     return(new HeroPower()
     {
         CardId = heroPower.Card.AssetId,
         Cost = heroPower.Cost,
         Exhausted = heroPower.IsExhausted
     });
 }
Пример #3
0
        /// <summary>Builds a new subclass of entity that can be added to a SabberStone game instance.</summary>
        /// <param name="controller">The controller of the entity.</param>
        /// <param name="card">The card from which the entity must be derived.</param>
        /// <param name="tags">The tags preset for the entity.</param>
        /// <param name="zone">The zone in which the entity must spawn.</param>
        /// <param name="id">The EntityID to assign to the newly created entity.</param>
        /// <returns></returns>
        /// <exception cref="EntityException"></exception>
        public static IPlayable FromCard(Controller controller, Card card, Dictionary <GameTag, int> tags = null, IZone zone = null, int id = -1)
        {
            tags = tags ?? new Dictionary <GameTag, int>();
            tags[GameTag.ENTITY_ID]  = id > 0 ? id : controller.Game.NextId;
            tags[GameTag.CONTROLLER] = controller.PlayerId;
            tags[GameTag.ZONE]       = zone != null ? (int)zone.Type : 0;
            //tags[GameTag.CARD_ID] = card.AssetId;

            IPlayable result = null;

            switch (card.Type)
            {
            case CardType.MINION:
                result = new Minion(controller, card, tags);
                break;

            case CardType.SPELL:
                result = new Spell(controller, card, tags);
                break;

            case CardType.WEAPON:
                result = new Weapon(controller, card, tags);
                break;

            case CardType.HERO:

                // removing this because it's always the cards health or it is given by previous heros like for deathknight
                //tags[GameTag.HEALTH] = card[GameTag.HEALTH];

                tags[GameTag.ZONE] = (int)Enums.Zone.PLAY;
                //tags[GameTag.FACTION] = card[GameTag.FACTION];
                tags[GameTag.CARDTYPE] = card[GameTag.CARDTYPE];
                //tags[GameTag.RARITY] = card[GameTag.RARITY];
                //tags[GameTag.HERO_POWER] = card[GameTag.HERO_POWER];

                result = new Hero(controller, card, tags);
                break;

            case CardType.HERO_POWER:
                tags[GameTag.COST] = card[GameTag.COST];
                tags[GameTag.ZONE] = (int)Enums.Zone.PLAY;
                //tags[GameTag.FACTION] = card[GameTag.FACTION];
                tags[GameTag.CARDTYPE] = card[GameTag.CARDTYPE];
                //tags[GameTag.RARITY] = card[GameTag.RARITY];
                //tags[GameTag.TAG_LAST_KNOWN_COST_IN_HAND] = card[GameTag.COST];
                result = new HeroPower(controller, card, tags);
                break;

            default:
                throw new EntityException($"Couldn't create entity, because of an unknown cardType {card.Type}.");
            }

            // add entity to the game dic
            controller.Game.IdEntityDic.Add(result.Id, result);

            // add power history full entity
            if (controller.Game.History)
            {
                controller.Game.PowerHistory.Add(PowerHistoryBuilder.FullEntity(result));
            }

            // add entity to the appropriate zone if it was given
            zone?.Add(result);

            if (result.ChooseOne)
            {
                result.ChooseOnePlayables[0] =
                    id < 0 ? FromCard(controller,
                                      Cards.FromId(result.Card.Id + "a"),
                                      new Dictionary <GameTag, int>
                {
                    [GameTag.CREATOR]     = result.Id,
                    [GameTag.PARENT_CARD] = result.Id
                },
                                      controller.SetasideZone) :
                    controller.SetasideZone.GetAll.Find(p => p[GameTag.CREATOR] == result.Id && p.Card.Id == result.Card.Id + "a");

                result.ChooseOnePlayables[1] =
                    id < 0 ? FromCard(controller,
                                      Cards.FromId(result.Card.Id + "b"),
                                      new Dictionary <GameTag, int>
                {
                    [GameTag.CREATOR]     = result.Id,
                    [GameTag.PARENT_CARD] = result.Id
                },
                                      controller.SetasideZone) :
                    controller.SetasideZone.GetAll.Find(p => p[GameTag.CREATOR] == result.Id && p.Card.Id == result.Card.Id + "b");
            }

            return(result);
        }
Пример #4
0
        public static List <Option> PythonOptions(this Controller c, int gameId)
        {
            if (c.Choice != null)
            {
                if (c.Choice.ChoiceType == ChoiceType.GENERAL)
                {
                    return(c.Choice.Choices.Select(p => new Option(gameId, p, c.Game.IdEntityDic[p].Card.Name)).ToList());
                }

                throw new NotImplementedException();
            }

            int           controllerId = c.Id;
            List <Option> allOptions   = ManagedObjects.OptionBuffers[gameId];

            allOptions.Add(new Option(gameId, EndTurn));

            #region PlayCardTasks
            int  mana            = c.RemainingMana;
            int  zonePosRange    = c.BoardZone.Count;
            bool?spellCostHealth = null;

            Character[] allTargets      = null;
            Minion[]    friendlyMinions = null;
            Minion[]    enemyMinions    = null;
            Minion[]    allMinions      = null;
            Character[] allFriendly     = null;
            Character[] allEnemies      = null;

            ReadOnlySpan <IPlayable> handSpan = c.HandZone.GetSpan();
            for (int i = 0; i < handSpan.Length; i++)
            {
                if (!handSpan[i].ChooseOne || c.ChooseBoth)
                {
                    GetPlayCardTasks(handSpan[i]);
                }
                else
                {
                    IPlayable[] playables = handSpan[i].ChooseOnePlayables;
                    for (int j = 1; j < 3; j++)
                    {
                        GetPlayCardTasks(handSpan[i], playables[j - 1], j);
                    }
                }
            }
            #endregion

            #region HeroPowerTask
            HeroPower power         = c.Hero.HeroPower;
            Card      heroPowerCard = power.Card;
            if (!power.IsExhausted && mana >= power.Cost &&
                !c.HeroPowerDisabled && !heroPowerCard.HideStat)
            {
                if (heroPowerCard.ChooseOne)
                {
                    if (c.ChooseBoth)
                    {
                        allOptions.Add(new Option(gameId, API.Option.Types.PlayerTaskType.HeroPower, source: power));
                    }
                    else
                    {
                        allOptions.Add(new Option(gameId, API.Option.Types.PlayerTaskType.HeroPower, subOption: 1, source: power));
                        allOptions.Add(new Option(gameId, API.Option.Types.PlayerTaskType.HeroPower, subOption: 2, source: power));
                    }
                }
                else
                {
                    if (heroPowerCard.IsPlayableByCardReq(c))
                    {
                        Character[] targets = GetTargets(heroPowerCard);
                        if (targets != null)
                        {
                            for (int i = 0; i < targets.Length; i++)
                            {
                                allOptions.Add(new Option(gameId, API.Option.Types.PlayerTaskType.HeroPower,
                                                          0, Option.getPosition(targets[i], controllerId),
                                                          source: power, target: targets[i]));
                            }
                        }
                        else
                        {
                            allOptions.Add(new Option(gameId, API.Option.Types.PlayerTaskType.HeroPower, source: power));
                        }
                    }
                }
            }
            #endregion

            #region MinionAttackTasks
            Minion[] attackTargets             = null;
            bool     isOpHeroValidAttackTarget = false;
            var      boardSpan = c.BoardZone.GetSpan();
            for (int j = 0; j < boardSpan.Length; j++)
            {
                Minion minion = boardSpan[j];

                if (minion.IsExhausted && (!minion.HasCharge || minion.NumAttacksThisTurn != 0))
                {
                    continue;
                }
                if (minion.IsFrozen || minion.AttackDamage == 0 || minion.CantAttack || minion.Untouchable)
                {
                    continue;
                }

                GenerateAttackTargets();

                for (int i = 0; i < attackTargets.Length; i++)
                {
                    allOptions.Add(new Option(gameId, MinionAttack, j + 1,
                                              Option.getEnemyPosition(attackTargets[i]), source: minion, target: attackTargets[i]));
                }

                if (isOpHeroValidAttackTarget && !(minion.CantAttackHeroes || minion.AttackableByRush))
                {
                    allOptions.Add(new Option(gameId, MinionAttack, j + 1, Option.OP_HERO_POSITION,
                                              source: minion, target: c.Opponent.Hero));
                }
            }
            #endregion

            #region HeroAttackTaskts
            Hero hero = c.Hero;

            if ((!hero.IsExhausted || (hero.ExtraAttacksThisTurn > 0 && hero.ExtraAttacksThisTurn >= hero.NumAttacksThisTurn)) &&
                hero.AttackDamage > 0 && !hero.IsFrozen)
            {
                GenerateAttackTargets();

                for (int i = 0; i < attackTargets.Length; i++)
                {
                    allOptions.Add(new Option(gameId, HeroAttack, 0,
                                              Option.getEnemyPosition(attackTargets[i]), source: hero, target: attackTargets[i]));
                }

                if (isOpHeroValidAttackTarget && !hero.CantAttackHeroes)
                {
                    allOptions.Add(new Option(gameId, HeroAttack, 0, Option.OP_HERO_POSITION,
                                              source: hero, target: c.Opponent.Hero));
                }
            }
            #endregion

            return(allOptions);

            #region local functions
            void GetPlayCardTasks(in IPlayable playable, in IPlayable chooseOnePlayable = null, int subOption = -1)
            {
                Card card = chooseOnePlayable?.Card ?? playable.Card;

                if (!spellCostHealth.HasValue)
                {
                    spellCostHealth = c.ControllerAuraEffects[GameTag.SPELLS_COST_HEALTH] == 1;
                }

                bool healthCost = (playable.AuraEffects?.CardCostHealth ?? false) ||
                                  (spellCostHealth.Value && playable.Card.Type == CardType.SPELL);

                if (!healthCost && (playable.Cost > mana || playable.Card.HideStat))
                {
                    return;
                }

                // check PlayableByPlayer
                switch (playable.Card.Type)
                {
                //	REQ_MINION_CAP
                case CardType.MINION when c.BoardZone.IsFull:
                    return;

                case CardType.SPELL:
                {
                    if (card.IsSecret)
                    {
                        if (c.SecretZone.IsFull)                                 // REQ_SECRET_CAP
                        {
                            return;
                        }
                        if (c.SecretZone.Any(p => p.Card.AssetId == card.AssetId))                                 // REQ_UNIQUE_SECRET
                        {
                            return;
                        }
                    }

                    if (card.IsQuest && c.SecretZone.Quest != null)
                    {
                        return;
                    }
                    break;
                }
                }

                {
                    if (!card.IsPlayableByCardReq(c))
                    {
                        return;
                    }

                    Character[] targets = GetTargets(card);

                    int sourcePosition = playable.ZonePosition;

                    // Card doesn't require any targets
                    if (targets == null)
                    {
                        if (playable is Minion)
                        {
                            for (int i = 0; i <= zonePosRange; i++)
                            {
                                allOptions.Add(new Option(gameId, PlayCard, sourcePosition, i + 1, subOption,
                                                          source: playable));
                            }
                        }
                        else
                        {
                            allOptions.Add(new Option(gameId, PlayCard, sourcePosition, -1, subOption,
                                                      source: playable));
                        }
                    }
                    else
                    {
                        if (targets.Length == 0)
                        {
                            if (card.MustHaveTargetToPlay)
                            {
                                return;
                            }

                            if (playable is Minion)
                            {
                                for (int i = 0; i <= zonePosRange; i++)
                                {
                                    allOptions.Add(new Option(gameId, PlayCard, sourcePosition, i + 1, subOption,
                                                              source: playable));
                                }
                            }
                            else
                            {
                                allOptions.Add(new Option(gameId, PlayCard, sourcePosition, -1, subOption,
                                                          source: playable));
                            }
                        }
                        else
                        {
                            for (int j = 0; j < targets.Length; j++)
                            {
                                ICharacter target = targets[j];
                                if (playable is Minion)
                                {
                                    //for (int i = 0; i <= zonePosRange; i++)
                                    //    allOptions.Add(PlayCardTask.Any(c, playable, target, i, subOption,
                                    //        true));
                                    continue;
                                }
                                else
                                {
                                    allOptions.Add(new Option(gameId, PlayCard, sourcePosition,
                                                              Option.getPosition(target, controllerId), subOption,
                                                              source: playable, target: target));
                                }
                            }
                        }
                    }
                }
            }

            // Returns null if targeting is not required
            // Returns 0 Array if there is no available target
            Character[] GetTargets(Card card)
            {
                // Check it needs additional validation
                if (!card.TargetingAvailabilityPredicate?.Invoke(c, card) ?? false)
                {
                    return(null);
                }

                Character[] targets;

                switch (card.TargetingType)
                {
                case TargetingType.None:
                    return(null);

                case TargetingType.All:
                    if (allTargets == null)
                    {
                        if (c.Opponent.Hero.HasStealth)
                        {
                            allTargets    = new Character[GetFriendlyMinions().Length + GetEnemyMinions().Length + 1];
                            allTargets[0] = c.Hero;
                            Array.Copy(GetAllMinions(), 0, allTargets, 1, allMinions.Length);
                        }
                        else
                        {
                            allTargets    = new Character[GetFriendlyMinions().Length + GetEnemyMinions().Length + 2];
                            allTargets[0] = c.Hero;
                            allTargets[1] = c.Opponent.Hero;
                            Array.Copy(GetAllMinions(), 0, allTargets, 2, allMinions.Length);
                        }
                    }
                    targets = allTargets;
                    break;

                case TargetingType.FriendlyCharacters:
                    if (allFriendly == null)
                    {
                        allFriendly    = new Character[GetFriendlyMinions().Length + 1];
                        allFriendly[0] = c.Hero;
                        Array.Copy(friendlyMinions, 0, allFriendly, 1, friendlyMinions.Length);
                    }
                    targets = allFriendly;
                    break;

                case TargetingType.EnemyCharacters:
                    if (allEnemies == null)
                    {
                        if (!c.Opponent.Hero.HasStealth)
                        {
                            allEnemies    = new Character[GetEnemyMinions().Length + 1];
                            allEnemies[0] = c.Opponent.Hero;
                            Array.Copy(enemyMinions, 0, allEnemies, 1, enemyMinions.Length);
                        }
                        else
                        {
                            allEnemies = GetEnemyMinions();
                        }
                    }
                    targets = allEnemies;
                    break;

                case TargetingType.AllMinions:
                    targets = GetAllMinions();
                    break;

                case TargetingType.FriendlyMinions:
                    targets = GetFriendlyMinions();
                    break;

                case TargetingType.EnemyMinions:
                    targets = GetEnemyMinions();
                    break;

                case TargetingType.Heroes:
                    targets = !c.Opponent.Hero.HasStealth
                                                        ? new[] { c.Hero, c.Opponent.Hero }
                                                        : new[] { c.Hero };
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                // Filtering for target_if_available
                TargetingPredicate p = card.TargetingPredicate;

                if (p != null)
                {
                    if (card.Type == CardType.SPELL || card.Type == CardType.HERO_POWER)
                    {
                        Character[] buffer = new Character[targets.Length];
                        int         i      = 0;
                        for (int j = 0; j < targets.Length; ++j)
                        {
                            if (!p(targets[j]) || targets[j].CantBeTargetedBySpells)
                            {
                                continue;
                            }
                            buffer[i] = targets[j];
                            i++;
                        }

                        if (i != targets.Length)
                        {
                            Character[] result = new Character[i];
                            Array.Copy(buffer, result, i);
                            return(result);
                        }
                        return(buffer);
                    }
                    else
                    {
                        if (!card.TargetingAvailabilityPredicate?.Invoke(c, card) ?? false)
                        {
                            return(null);
                        }

                        Character[] buffer = new Character[targets.Length];
                        int         i      = 0;
                        for (int j = 0; j < targets.Length; ++j)
                        {
                            if (!p(targets[j]))
                            {
                                continue;
                            }
                            buffer[i] = targets[j];
                            i++;
                        }

                        if (i != targets.Length)
                        {
                            Character[] result = new Character[i];
                            Array.Copy(buffer, result, i);
                            return(result);
                        }
                        return(buffer);
                    }
                }
                else if (card.Type == CardType.SPELL || card.Type == CardType.HERO_POWER)
                {
                    Character[] buffer = new Character[targets.Length];
                    int         i      = 0;
                    for (int j = 0; j < targets.Length; ++j)
                    {
                        if (targets[j].CantBeTargetedBySpells)
                        {
                            continue;
                        }
                        buffer[i] = targets[j];
                        i++;
                    }

                    if (i != targets.Length)
                    {
                        Character[] result = new Character[i];
                        Array.Copy(buffer, result, i);
                        return(result);
                    }
                    return(buffer);
                }

                return(targets);

                Minion[] GetFriendlyMinions()
                {
                    return(friendlyMinions ?? (friendlyMinions = c.BoardZone.GetAll()));
                }

                Minion[] GetAllMinions()
                {
                    if (allMinions != null)
                    {
                        return(allMinions);
                    }

                    allMinions = new Minion[GetEnemyMinions().Length + GetFriendlyMinions().Length];
                    Array.Copy(enemyMinions, allMinions, enemyMinions.Length);
                    Array.Copy(friendlyMinions, 0, allMinions, enemyMinions.Length, friendlyMinions.Length);

                    return(allMinions);
                }
            }

            void GenerateAttackTargets()
            {
                if (attackTargets != null)
                {
                    return;
                }

                Minion[] eMinions = GetEnemyMinions();
                //var taunts = new Minion[eMinions.Length];
                Minion[] taunts = null;
                int      tCount = 0;

                for (int i = 0; i < eMinions.Length; i++)
                {
                    if (eMinions[i].HasTaunt)
                    {
                        if (taunts == null)
                        {
                            taunts = new Minion[eMinions.Length];
                        }
                        taunts[tCount] = eMinions[i];
                        tCount++;
                    }
                }

                if (tCount > 0)
                {
                    var targets = new Minion[tCount];
                    Array.Copy(taunts, targets, tCount);
                    attackTargets             = targets;
                    isOpHeroValidAttackTarget = false;                      // some brawls allow taunt heros and c should be fixed
                    return;
                }
                attackTargets = eMinions;

                isOpHeroValidAttackTarget =
                    !c.Opponent.Hero.IsImmune && !c.Opponent.Hero.HasStealth;
            }

            Minion[] GetEnemyMinions()
            {
                return(enemyMinions ?? (enemyMinions = c.Opponent.BoardZone.GetAll(p => !p.HasStealth && !p.IsImmune)));
            }

            #endregion
        }
Пример #5
0
 public HeroPower(SabberStoneCore.Model.Entities.HeroPower heroPower)
 {
     cardId_    = heroPower.Card.AssetId;
     cost_      = heroPower.Cost;
     exhausted_ = heroPower.IsExhausted;
 }
Пример #6
0
 public HeroPower(SabberEntities.HeroPower playable)
 {
     CardId    = playable.Card.AssetId;
     Cost      = playable.Cost;
     Exhausted = playable.IsExhausted;
 }