Пример #1
0
        private static Game CreatePartiallyObservableGame(Game fullGame)
        {
            Game game = fullGame.Clone();

            SabberStoneCore.Model.Entities.Controller op   = game.CurrentOpponent;
            SabberStoneCore.Model.Zones.HandZone      hand = op.HandZone;
            ReadOnlySpan <IPlayable> span = hand.GetSpan();

            for (int i = span.Length - 1; i >= 0; --i)
            {
                hand.Remove(span[i]);
                hand.Add(new Unknown(in op, PlaceHolder, span[i].Id));
            }
            game.AuraUpdate();
            span = op.DeckZone.GetSpan();
            for (int i = 0; i < span.Length; i++)
            {
                span[i].ActivatedTrigger?.Remove();
            }
            var deck = new SabberStoneCore.Model.Zones.DeckZone(op);

            for (int i = 0; i < span.Length; i++)
            {
                span[i].ActivatedTrigger?.Remove();
                deck.Add(new Unknown(in op, PlaceHolder, span[i].Id));
            }
            op.DeckZone = deck;
            return(game);
        }
Пример #2
0
 public Controller(SabberStoneCore.Model.Entities.Controller controller)
 {
     id_             = controller.PlayerId;
     hero_           = new Hero(controller.Hero);
     boardZone_      = new BoardZone(controller.BoardZone);
     handZone_       = new HandZone(controller.HandZone);
     secretZone_     = new SecretZone(controller.SecretZone);
     deckZone_       = new DeckZone(controller.DeckZone);
     playState_      = (Types.PlayState)controller.PlayState;
     baseMana_       = controller.BaseMana;
     remainingMana_  = controller.RemainingMana;
     overloadLocked_ = controller.OverloadLocked;
     overloadOwed_   = controller.OverloadOwed;
 }
Пример #3
0
 public Controller(SabberEntities.Controller controller)
 {
     Id             = controller.PlayerId;
     PlayState      = (int)controller.PlayState;
     BaseMana       = controller.BaseMana;
     RemainingMana  = controller.RemainingMana;
     OverloadLocked = controller.OverloadLocked;
     OverloadOwed   = controller.OverloadOwed;
     Hero           = new Hero(controller.Hero);
     HandZone       = new HandZone(controller.HandZone);
     BoardZone      = new BoardZone(controller.BoardZone);
     SecretZone     = new SecretZone(controller.SecretZone);
     DeckZone       = new DeckZone(controller.DeckZone);
 }
Пример #4
0
 private Controller GetController(SabberStoneCore.Model.Entities.Controller controller)
 {
     return(new Controller()
     {
         Id = controller.PlayerId,
         Hero = GetHero(controller.Hero),
         BoardZone = GetBoardZone(controller.BoardZone),
         HandZone = GetHandZone(controller.HandZone),
         SecretZone = GetSecretZone(controller.SecretZone),
         DeckZone = GetDeckZone(controller.DeckZone),
         PlayState = (Types.PlayState)controller.PlayState,
         BaseMana = controller.BaseMana,
         RemainingMana = controller.RemainingMana,
         OverloadLocked = controller.OverloadLocked,
         OverloadOwed = controller.OverloadOwed
     });
 }
Пример #5
0
        public void Execute()
        {
            _game.Process(PlayerTask);

            SabberStoneCore.Model.Entities.Controller controller = _game.ControllerById(_playerId);

            _gameState = _game.State == State.RUNNING ? 0 : 1;
            //: (controller.PlayState == PlayState.WON ? 1 : -1);

            _endTurn = _game.CurrentPlayer.Id != _playerId ? 1 : 0;

            Hash = _game.Hash(GameTag.LAST_CARD_PLAYED, GameTag.ENTITY_ID);

            //if (IsEndTurn || !IsRunning)
            //{
            Scoring.Controller = controller;
            Score = Scoring.Rate();
            //}
        }
Пример #6
0
        private static Game CreatePartiallyObservableGame(Game fullGame)
        {
            Game game = fullGame.Clone();

            SabberStoneCore.Model.Entities.Controller op   = game.CurrentOpponent;
            SabberStoneCore.Model.Entities.Controller p    = game.CurrentPlayer;
            SabberStoneCore.Model.Zones.HandZone      hand = op.HandZone;
            int opHandCount = hand.Count;

            for (int i = 0; i < opHandCount; i++)
            {
                int id = hand[0].Id;
                hand.Remove(0);
                hand.Add(new Unknown(in op, PlaceHolder, id));
            }
            game.AuraUpdate();
            int opDeckCount = op.DeckZone.Count;

            for (int i = 0; i < opDeckCount; i++)
            {
                int id = op.DeckZone[i].Id;
                op.DeckZone[i].ActivatedTrigger?.Remove();
                op.DeckZone.Remove(0);
                op.DeckZone.Add(new Unknown(in op, PlaceHolder, id));
            }
            int myDeckCount = p.DeckZone.Count;

            for (int i = 0; i < myDeckCount; i++)
            {
                int id = p.DeckZone[i].Id;
                p.DeckZone[i].ActivatedTrigger?.Remove();
                p.DeckZone.Remove(0);
                p.DeckZone.Add(new Unknown(in p, PlaceHolder, id));
            }
            return(game);
        }
Пример #7
0
 public static unsafe int Options(this SabberStoneCore.Model.Entities.Controller c, in byte *mmfPtr)
Пример #8
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
        }
Пример #9
0
        public static PlayerTask GetPlayerTask(Option option, Game g)
        {
            const bool SkipPrePhase = true;
            Controller c            = g.CurrentPlayer;

            switch (option.Type)
            {
            case Choose:
                return(ChooseTask.Pick(c, option.Choice));

            case Concede:
                return(ConcedeTask.Any(c));

            case EndTurn:
                return(EndTurnTask.Any(c));

            case HeroAttack:
                return(HeroAttackTask.Any(c, GetOpponentTarget(option.TargetPosition), SkipPrePhase));

            case Option.Types.PlayerTaskType.HeroPower:
                return(HeroPowerTask.Any(c, GetTarget(option.TargetPosition), option.SubOption, SkipPrePhase));

            case MinionAttack:
                return(MinionAttackTask.Any(c, c.BoardZone[option.SourcePosition - 1], GetOpponentTarget(option.TargetPosition), SkipPrePhase));

            case PlayCard:
                IPlayable source = c.HandZone[option.SourcePosition];
                if (source.Card.Type == CardType.MINION)
                {
                    return(PlayCardTask.Any(c, source, null, option.TargetPosition - 1, option.SubOption, SkipPrePhase));
                }
                else
                {
                    return(PlayCardTask.Any(c, source, GetTarget(option.TargetPosition),
                                            0, option.SubOption, SkipPrePhase));
                }

            default:
                throw new ArgumentOutOfRangeException();
            }

            ICharacter GetOpponentTarget(int position)
            {
                if (position == Option.OP_HERO_POSITION)
                {
                    return(c.Opponent.Hero);
                }
                return(c.Opponent.BoardZone[position - 9]);
            }

            ICharacter GetTarget(int position)
            {
                if (position == -1)
                {
                    return(null);
                }
                if (position >= Option.OP_HERO_POSITION)
                {
                    return(GetOpponentTarget(position));
                }
                if (position == Option.HERO_POSITION)
                {
                    return(c.Hero);
                }
                return(c.BoardZone[position - 1]);
            }
        }
Пример #10
0
 public static PlayerTask OptionToPlayerTask(SabberStoneCore.Model.Entities.Controller c, in Option option)
Пример #11
0
 public override IPlayable Clone(Controller controller)
 {
     return(new Spell(controller, this));
 }
Пример #12
0
 /// <summary>
 /// A copy constructor.
 /// </summary>
 /// <param name="controller">The target <see cref="Controller"/> instance.</param>
 /// <param name="spell">The source <see cref="Spell"/>.</param>
 private Spell(Controller controlller, Spell spell) : base(controlller, spell)
 {
 }
Пример #13
0
 /// <summary>Initializes a new instance of the <see cref="Spell"/> class.</summary>
 /// <param name="controller">The controller.</param>
 /// <param name="card">The card.</param>
 /// <param name="tags">The tags.</param>
 /// <autogeneratedoc />
 public Spell(Controller controller, Card card, IDictionary <GameTag, int> tags)
     : base(controller, card, tags)
 {
     Game.Log(LogLevel.VERBOSE, BlockType.PLAY, "Spell", !Game.Logging ? "" : $"{card.Name} ({card.Class}) was created.");
 }