public Hero(SabberEntities.Hero playable) { CardClass = (int)playable.Card.Class; ATK = playable.AttackDamage; BaseHealth = playable.BaseHealth; Damage = playable.Damage; NumAttacksThisTurn = playable.NumAttacksThisTurn; Armor = playable.Armor; Exhausted = playable.IsExhausted; Stealth = playable.HasStealth; Immune = playable.IsImmune; HeroPower = new HeroPower(playable.HeroPower); Weapon = new Weapon(playable.Weapon); }
public Hero(SabberStoneCore.Model.Entities.Hero hero) { cardClass_ = (int)hero.Card.Class; atk_ = hero.AttackDamage; baseHealth_ = hero.BaseHealth; damage_ = hero.Damage; numAttacksThisTurn_ = hero.NumAttacksThisTurn; armor_ = hero.Armor; exhausted_ = hero.IsExhausted; stealth_ = hero.HasStealth; immune_ = hero.IsImmune; power_ = new HeroPower(hero.HeroPower); if (hero.Weapon != null) { weapon_ = new Weapon(hero.Weapon); } }
private Hero GetHero(SabberStoneCore.Model.Entities.Hero hero) { return(new Hero() { CardClass = (int)hero.Card.Class, Atk = hero.AttackDamage, BaseHealth = hero.BaseHealth, Damage = hero.Damage, NumAttacksThisTurn = hero.NumAttacksThisTurn, Armor = hero.Armor, Exhausted = hero.IsExhausted, Stealth = hero.HasStealth, Immune = hero.IsImmune, Power = GetHeroPower(hero.HeroPower), Weapon = hero.Weapon != null?GetWeapon(hero.Weapon) : null }); }
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 }