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); }
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; }
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); }
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 }); }
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(); //} }
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); }
public static unsafe int Options(this SabberStoneCore.Model.Entities.Controller c, in byte *mmfPtr)
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 }
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]); } }
public static PlayerTask OptionToPlayerTask(SabberStoneCore.Model.Entities.Controller c, in Option option)
public override IPlayable Clone(Controller controller) { return(new Spell(controller, this)); }
/// <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) { }
/// <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."); }