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}"); }
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); }
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(); }
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); }
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); }
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); }
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; }
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); } }
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; }
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!"); }
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--; } }
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)); } }
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); }
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}'"); }
/// <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); } }
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."); }
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."); }
public void GainArmor(IPlayable source, int armor) { Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", $"{this} gaining armor for {armor}."); Armor += armor; }
public IPlayable Destroy() { ToBeDestroyed = true; Game.Log(LogLevel.VERBOSE, BlockType.PLAY, "Playable", $"{this} just got set to be destroyed."); return(this); }
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); }