public TaskState Process() { CurrentTask = TaskList.OrderBy(p => p.Source.OrderOfPlay).First(); TaskList.Remove(CurrentTask); Game.Log(LogLevel.VERBOSE, BlockType.TRIGGER, "TaskQueue", $"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 override TaskState Process() { switch (Controller.Choice.ChoiceType) { case ChoiceType.MULLIGAN: Generic.ChoiceMulligan.Invoke(Controller, Choices); if (Controller.Game.History) { Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, Controller.Id, "", 7, 0)); } Controller.MulliganState = Enums.Mulligan.DONE; if (Controller.Game.History) { Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } return(TaskState.COMPLETE); case ChoiceType.GENERAL: if (!Generic.ChoicePick.Invoke(Controller, Choices[0])) { return(TaskState.STOP); } Controller.NumOptionsPlayedThisTurn++; Game.ProcessTasks(); Game.DeathProcessingAndAuraUpdate(); return(TaskState.COMPLETE); case ChoiceType.INVALID: throw new NotImplementedException(); } return(TaskState.STOP); }
public override TaskState Process() { switch (Controller.Choice.ChoiceType) { case ChoiceType.MULLIGAN: Generic.ChoiceMulligan.Invoke(Controller, Choices); if (Controller.Game.History) { Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, Controller.Id, "", 7, 0)); } Controller.MulliganState = Enums.Mulligan.DONE; if (Controller.Game.History) { Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } return(TaskState.COMPLETE); case ChoiceType.GENERAL: Generic.ChoicePick.Invoke(Controller, Choices[0]); Controller.Game.NextStep = Step.MAIN_CLEANUP; return(TaskState.COMPLETE); case ChoiceType.INVALID: throw new NotImplementedException(); } return(TaskState.STOP); }
public TaskState Process() { ISimpleTask currentTask = CurrentQueue.Dequeue(); CurrentTask = currentTask; //if (currentTask is StateTaskList tasks) // tasks.Stack = new TaskStack(_game); _game.Log(LogLevel.VERBOSE, BlockType.TRIGGER, "TaskQueue", !_game.Logging ? "" : $"LazyTask[{currentTask.Source}]: '{currentTask.GetType().Name}' is processed!" + $"'{currentTask.Source.Card.Text?.Replace("\n", " ")}'"); if (_game.History) { _game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(currentTask.IsTrigger ? BlockType.TRIGGER : 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(); CurrentTask = null; return(success); }
/// <summary>Initializes a new instance of the <see cref="Game"/> class.</summary> /// <param name="gameConfig">The game configuration.</param> /// <param name="setupHeroes"></param> public Game(GameConfig gameConfig, bool setupHeroes = true) : base(null, Card.CardGame, new Dictionary <GameTag, int> { [GameTag.ENTITY_ID] = GAME_ENTITYID, [GameTag.ZONE] = (int)Enums.Zone.PLAY, [GameTag.CARDTYPE] = (int)CardType.GAME }) { _gameConfig = gameConfig; Game = this; GamesEventManager = new GameEventManager(this); _players[0] = new Controller(this, gameConfig.Player1Name, 1, 2); _players[1] = new Controller(this, gameConfig.Player2Name, 2, 3); // add power history create game if (History) { PowerHistory.Add(PowerHistoryBuilder.CreateGame(this, _players)); } if (setupHeroes) { _players[0].AddHeroAndPower(Cards.HeroCard(gameConfig.Player1HeroClass)); _players[1].AddHeroAndPower(Cards.HeroCard(gameConfig.Player2HeroClass)); } TaskQueue = new TaskQueue(this); TaskStack = new TaskStack(this); }
private void DeApply(Minion m) { for (int i = 0; i < _effects.Length; i++) { _effects[i].RemoveAuraFrom(m); } if (EnchantmentCard != null && (_history || EnchantmentCard.Power.Trigger != null)) { int cardId = EnchantmentCard.AssetId; List <Enchantment> enchantments = m.AppliedEnchantments; for (int i = enchantments.Count - 1; i >= 0; i--) { if (enchantments[i].Creator == _owner && enchantments[i].Card.AssetId == cardId) { enchantments.RemoveAt(i); break; } } if (_history) { for (int i = 0; i < _effects.Length; i++) { _owner.Game.PowerHistory.Add( PowerHistoryBuilder.TagChange(_owner.Id, _effects[i].Tag, _owner[_effects[i].Tag])); } } } }
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", $"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(); }
/// <summary> /// Sets the native value without any trigger activated. /// </summary> /// <param name="tag"></param> /// <param name="value"></param> public void SetNativeGameTag(GameTag tag, int value) { _data[tag] = value; if (Game.History && (int)tag < 1000) { Game.PowerHistory.Add(PowerHistoryBuilder.TagChange(Id, tag, value)); } }
public static IPlayable Draw(Controller c, int index) { IPlayable playable = c.DeckZone.Remove(index); c.Game.Log(LogLevel.INFO, BlockType.ACTION, "DrawPhase", !c.Game.Logging ? "" : $"{c.Name} draws {playable}"); c.NumCardsDrawnThisTurn++; c.NumCardsDrawnThisGame++; c.LastCardDrawn = playable.Id; if (AddHandPhase.Invoke(c, playable)) { // DrawTrigger vs TOPDECK ?? not sure which one is first Game game = c.Game; game.TaskQueue.StartEvent(); game.TriggerManager.OnDrawTrigger(playable); game.ProcessTasks(); game.TaskQueue.EndEvent(); ISimpleTask task = playable.Power?.TopDeckTask; if (task != null) { if (game.History) { // TODO: triggerkeyword: TOPDECK game.PowerHistory.Add( PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, playable.Id, "", 0, 0)); } c.SetasideZone.Add(c.HandZone.Remove(playable)); game.Log(LogLevel.INFO, BlockType.TRIGGER, "TOPDECK", !game.Logging ? "" : $"{playable}'s TOPDECK effect is activated."); task.Process(game, c, playable, null); if (game.History) { game.PowerHistory.Add( PowerHistoryBuilder.BlockEnd()); } } } c.DeckZone.ResetPositions(); return(playable); }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING && NEXTSTEP = MAIN_READY /// </summary> public void MainReady() { if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, CurrentPlayer.Id, "", 1, 0)); } Characters.ForEach(p => { p.NumTurnsInPlay++; p.NumAttacksThisTurn = 0; }); Heroes.ForEach(p => { p.Controller.NumCardsDrawnThisTurn = 0; p.Controller.NumCardsPlayedThisTurn = 0; p.Controller.NumMinionsPlayedThisTurn = 0; p.Controller.NumOptionsPlayedThisTurn = 0; p.Controller.NumFriendlyMinionsThatDiedThisTurn = 0; }); CurrentPlayer.Hero.IsExhausted = false; CurrentPlayer.Hero.Power.IsExhausted = false; foreach (var e in CurrentPlayer.BoardZone) { e.IsSummoned = false; e.IsExhausted = false; } // De-activate combo buff CurrentPlayer.IsComboActive = false; CurrentPlayer.NumMinionsPlayerKilledThisTurn = 0; CurrentOpponent.NumMinionsPlayerKilledThisTurn = 0; CurrentPlayer.NumFriendlyMinionsThatAttackedThisTurn = 0; NumMinionsKilledThisTurn = 0; CurrentPlayer.HeroPowerActivationsThisTurn = 0; CurrentPlayer.NumElementalsPlayedLastTurn = CurrentPlayer.NumElementalsPlayedThisTurn; CurrentPlayer.NumElementalsPlayedThisTurn = 0; if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } // set next step NextStep = Step.MAIN_START_TRIGGERS; }
public void AddWeapon(Weapon weapon) { RemoveWeapon(); weapon.SetOrderOfPlay("WEAPON"); Weapon = weapon; Weapon[GameTag.ZONE] = (int)Enums.Zone.PLAY; Weapon[GameTag.ZONE_POSITION] = 0; if (Game.History) { Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.POWER, Weapon.Id, "", -1, 0)); Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } EquippedWeapon = weapon.Id; }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING && NEXTSTEP = MAIN_DRAW /// </summary> public void MainDraw() { if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, CurrentPlayer.Id, "", 0, 0)); // turn start effect } //CurrentPlayer.NumCardsToDraw = 1; Generic.Draw(CurrentPlayer); if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } // set next step NextStep = Step.MAIN_START; }
private void Apply(Minion m) { for (int i = 0; i < _effects.Length; i++) { _effects[i].ApplyAuraTo(m); } if (EnchantmentCard != null && _history) { Enchantment.GetInstance(m.Controller, _owner, m, in EnchantmentCard); for (int i = 0; i < _effects.Length; i++) { _owner.Game.PowerHistory.Add( PowerHistoryBuilder.TagChange(_owner.Id, _effects[i].Tag, _owner[_effects[i].Tag])); } } }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING && NEXTSTEP = MAIN_START_TRIGGERS /// </summary> public void MainStartTriggers() { CurrentPlayer.TurnStart = true; DeathProcessingAndAuraUpdate(); if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, CurrentPlayer.Id, "", 8, 0)); } if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } // set next step NextStep = Step.MAIN_RESOURCE; }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING && NEXTSTEP = BEGIN_DRAW /// </summary> public void BeginDraw() { Log(LogLevel.VERBOSE, BlockType.PLAY, "Game", $"Begin Draw."); //FirstPlayer.NumCardsToDraw = 3; //FirstPlayer.Opponent.NumCardsToDraw = 4; _players.ToList().ForEach(p => { // quest draw if there is var quest = p.DeckZone.GetAll.Where(q => q is Spell && ((Spell)q).IsQuest).FirstOrDefault(); Generic.Draw(p, quest != null ? quest : null); Generic.Draw(p); Generic.Draw(p); if (p != FirstPlayer) { // 4th card for second player Generic.Draw(p); var coin = FromCard(FirstPlayer.Opponent, Cards.FromId("GAME_005"), new Dictionary <GameTag, int>() { [GameTag.ZONE] = (int)Enums.Zone.HAND, [GameTag.CARDTYPE] = (int)CardType.SPELL, [GameTag.CREATOR] = FirstPlayer.Opponent.PlayerId }); Generic.AddHandPhase(FirstPlayer.Opponent, coin); } p.NumTurnsLeft = 1; }); Player1.TimeOut = 75; Player2.TimeOut = 75; // ending mulligan draw block if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } NextStep = _gameConfig.SkipMulligan ? Step.MAIN_BEGIN : Step.BEGIN_MULLIGAN; }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING && NEXTSTEP = MAIN_NEXT /// </summary> public void MainNext() { if (History) { PowerHistoryBuilder.BlockStart(Enums.BlockType.TRIGGER, this.Id, "", -1, 0); } CurrentPlayer.NumTurnsLeft = 0; CurrentOpponent.NumTurnsLeft = 1; // After a player ends their turn (just before the next player's Start of // Turn Phase), un-Freeze all characters they control that are Frozen, // don't have summoning sickness (or do have Charge) and have not attacked // that turn. CurrentPlayer.BoardZone.GetAll.ForEach(p => { var minion = p as Minion; if (minion != null && minion.IsFrozen && minion.NumAttacksThisTurn == 0 && (!minion.IsSummoned || minion.HasCharge)) { minion.IsFrozen = false; } }); if (CurrentPlayer.Hero.IsFrozen && CurrentPlayer.Hero.NumAttacksThisTurn == 0) { CurrentPlayer.Hero.IsFrozen = false; } // set player for next turn ... CurrentPlayer = CurrentOpponent; // count next turn Turn++; Log(LogLevel.INFO, BlockType.PLAY, "Game", $"CurentPlayer {CurrentPlayer.Name}."); if (History) { PowerHistoryBuilder.BlockEnd(); } // set next step NextStep = Step.MAIN_READY; }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING && NEXTSTEP = MAIN_CLEANUP /// </summary> public void MainCleanUp() { if (History) { PowerHistoryBuilder.BlockStart(Enums.BlockType.TRIGGER, CurrentPlayer.Id, "", 5, 0); } DeathProcessingAndAuraUpdate(); if (History) { PowerHistoryBuilder.BlockEnd(); } // move forward if game isn't won by any player now! NextStep = _players.ToList().TrueForAll(p => p.PlayState == PlayState.PLAYING) ? Step.MAIN_ACTION : Step.FINAL_WRAPUP; }
public override bool Process() { Choice choice = Controller.Choice; if (choice == null) { return(false); } switch (choice.ChoiceType) { case ChoiceType.MULLIGAN: Generic.ChoiceMulligan.Invoke(Controller, Choices); if (Controller.Game.History) { Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, Controller.Id, "", 7, 0)); } Controller.MulliganState = Enums.Mulligan.DONE; if (Controller.Game.History) { Controller.Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } return(true); case ChoiceType.GENERAL: //Game.CurrentEventData = // new EventMetaData(Game.IdEntityDic[choice.SourceId], Game.IdEntityDic[Choices[0]]); if (!Generic.ChoicePick.Invoke(Controller, Game, Choices[0])) { return(false); } Controller.NumOptionsPlayedThisTurn++; Game.ProcessTasks(); Game.DeathProcessingAndAuraUpdate(); //Game.CurrentEventData = null; return(true); case ChoiceType.INVALID: throw new NotImplementedException(); } return(false); }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING && NEXTSTEP = MAIN_END /// </summary> public void MainEnd() { Log(LogLevel.INFO, BlockType.PLAY, "Game", $"End turn proccessed by player {CurrentPlayer}"); if (History) { PowerHistoryBuilder.BlockStart(Enums.BlockType.TRIGGER, CurrentPlayer.Id, "", 4, 0); } CurrentPlayer.TurnStart = false; DeathProcessingAndAuraUpdate(); if (History) { PowerHistoryBuilder.BlockEnd(); } // set next step NextStep = Step.MAIN_NEXT; }
public override TaskState Process() { if (Game.History) { Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.JOUST, Source.Id, "", 0, 0)); } IPlayable playable = Generic.JoustBlock.Invoke(Controller, _type); if (Game.History) { Game.PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } if (playable != null) { // add joust card winner to stack Playables = new List <IPlayable> { playable }; SuccessJoustTask.Game = Game; SuccessJoustTask.Controller = Controller; SuccessJoustTask.Source = Source; SuccessJoustTask.Target = Target; return(SuccessJoustTask.Process()); } if (FailedJoustTask != null) { FailedJoustTask.Game = Game; FailedJoustTask.Controller = Controller; FailedJoustTask.Source = Source; FailedJoustTask.Target = Target; return(FailedJoustTask.Process()); } Game.OnRandomHappened(true); return(TaskState.COMPLETE); }
/// <summary> /// Apply this Enchant's <see cref="Effect"/>s to the given entity. /// </summary> /// <param name="entity">The target entity.</param> /// <param name="num1">Integer value for GameTag.TAG_SCRIPT_DATA_NUM_1.</param> /// <param name="num2">Integer value for GameTag.TAG_SCRIPT_DATA_NUM_2.</param> public virtual void ActivateTo(IEntity entity, int num1 = -1, int num2 = -1) { IEffect[] effects = Effects; if (!UseScriptTag) { for (int i = 0; i < effects.Length; i++) { effects[i].ApplyTo(entity, IsOneTurnEffect); } } else { effects[0].ChangeValue(num1).ApplyTo(entity, IsOneTurnEffect); if (effects.Length >= 2) { if (num2 >= 0) { effects[1].ChangeValue(num2).ApplyTo(entity, IsOneTurnEffect); } else { effects[1].ChangeValue(num1).ApplyTo(entity, IsOneTurnEffect); } for (int i = 2; i < effects.Length; i++) { effects[i].ApplyTo(entity, IsOneTurnEffect); } } } if (entity.Game.History) { for (int i = 0; i < effects.Length; i++) { entity.Game.PowerHistory.Add( PowerHistoryBuilder.TagChange(entity.Id, effects[i].Tag, entity[effects[i].Tag])); } } }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING && NEXTSTEP = BEGIN_MULLIGAN /// </summary> public void BeginMulligan() { Log(LogLevel.VERBOSE, BlockType.PLAY, "Game", $"Begin Mulligan."); // starting mulligan draw block if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, this.Id, "", -1, 0)); } Player1.MulliganState = Mulligan.INPUT; Player2.MulliganState = Mulligan.INPUT; Generic.CreateChoice.Invoke(Player1, this, ChoiceType.MULLIGAN, ChoiceAction.HAND, Player1.HandZone.Select(p => p.Id).ToList()); Generic.CreateChoice.Invoke(Player2, this, ChoiceType.MULLIGAN, ChoiceAction.HAND, Player2.HandZone.Select(p => p.Id).ToList()); // ending mulligan draw block if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockEnd()); } }
/// <summary> /// Move destroyed entities from <see cref="Zone.PLAY"/> <see cref="Zone{T}"/> into /// <see cref="Zone.GRAVEYARD"/> /// </summary> public void GraveYard() { // remove dead weapons var heroesBadWeapons = Heroes.Where(p => p.Weapon != null && (p.Weapon.Durability == 0 || p.Weapon.ToBeDestroyed)).ToList(); heroesBadWeapons.ForEach(p => p.RemoveWeapon()); // check for dead minions to carry to the graveyard Minions.Where(p => p.IsDead).ToList().ForEach(p => { Log(LogLevel.INFO, BlockType.PLAY, "Game", $"{p} is Dead! Graveyard say 'Hello'!"); p.Zone.Remove(p); if (p.HasDeathrattle) { p.ApplyEnchantments(EnchantmentActivation.DEATHRATTLE, Enums.Zone.GRAVEYARD); } if (History) { PowerHistoryBuilder.BlockStart(BlockType.DEATHS, 1, "", 0, 0); } p.IsExhausted = false; p.Controller.GraveyardZone.Add(p); p.Controller.NumFriendlyMinionsThatDiedThisTurn++; CurrentPlayer.NumMinionsPlayerKilledThisTurn++; NumMinionsKilledThisTurn++; p.Damage = 0; if (History) { PowerHistoryBuilder.BlockEnd(); } }); // check for dead heroes var deadHeroes = Heroes.Where(p => p.IsDead).ToList(); deadHeroes.ForEach(p => p.Controller.PlayState = deadHeroes.Count > 1 ? PlayState.TIED : PlayState.LOSING); }
public override int this[GameTag t] { get { _data.TryGetValue(t, out int value); return(value + ControllerAuraEffects[t]); } set { //20200405 Connor - Turning off the logging for now //if (_logging) // Game.Log(LogLevel.DEBUG, BlockType.TRIGGER, "Entity", !Game.Logging ? "" : $"{this} set data {t} to {value}"); if (_history && (int)t < 1000) { if (value + ControllerAuraEffects[t] != this[t]) { Game.PowerHistory.Add(PowerHistoryBuilder.TagChange(Id, t, value)); } } _data[t] = value; } }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING. /// </summary> public void StartGame() { Log(LogLevel.INFO, BlockType.PLAY, "Game", "Starting new game now!"); // setting up the decks ... _gameConfig.Player1Deck?.ForEach(p => Entity.FromCard(Player1, p, null, Player1.DeckZone)); _gameConfig.Player2Deck?.ForEach(p => Entity.FromCard(Player2, p, null, Player2.DeckZone)); if (_gameConfig.FillDecks) { Player1.DeckZone.Fill(); Player2.DeckZone.Fill(); } // set gamestats State = State.RUNNING; _players.ToList().ForEach(p => p.PlayState = PlayState.PLAYING); // starting mulligan draw block if (History) { PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, this.Id, "", -1, 0)); } // getting first player FirstPlayer = _gameConfig.StartPlayer < 0 ? _players[Util.Random.Next(0, 2)] : _players[_gameConfig.StartPlayer - 1]; CurrentPlayer = FirstPlayer; Log(LogLevel.INFO, BlockType.PLAY, "Game", $"Starting Player is {CurrentPlayer.Name}."); // first turn Turn = 1; // set next step NextStep = Step.BEGIN_FIRST; }
/// <summary> /// Part of the state machine. /// Runs when STATE = RUNNING && NEXTSTEP = FINAL_WRAPUP /// </summary> public void FinalWrapUp() { if (History) { PowerHistoryBuilder.BlockStart(Enums.BlockType.TRIGGER, Id, "", -1, 0); } Heroes.ForEach(p => { if (p.Controller.PlayState == PlayState.LOSING || p.Controller.PlayState == PlayState.CONCEDED) { p.Controller.PlayState = PlayState.LOST; p.Controller.Opponent.PlayState = PlayState.WON; } }); if (History) { PowerHistoryBuilder.BlockEnd(); } // set next step NextStep = Step.FINAL_GAMEOVER; }
public void Update() { if (_triggerType != TriggerType.NONE) { if (_initialisationFunction != null) { _owner._costManager.UpdateAdaptiveEffect(_cachedValue); } else { if (!_isTriggered) { return; } if (_isAppliedThisTurn) { return; } _owner._costManager.UpdateAdaptiveEffect(_value); _isAppliedThisTurn = true; } } else { _owner._costManager.UpdateAdaptiveEffect(); } if (_owner.Game.History) { _owner.Game.PowerHistory.Add(PowerHistoryBuilder .TagChange(_owner.Id, GameTag.COST, _owner.Cost)); } }
/// <summary> /// Inflict damage onto this character. /// The actual amount still needs to be determined by the current /// state of the game. eg: The presence of immunity effects can cause /// the damage to be ignored. /// </summary> /// <param name="source"></param> /// <param name="damage"></param> /// <returns></returns> public int TakeDamage(IPlayable source, int damage) { var hero = this as Hero; var minion = this as Minion; if (minion != null && minion.Zone.Type != Enums.Zone.PLAY) { return(0); } bool fatigue = hero != null && this == source; if (fatigue) { hero.Fatigue = damage; } if (minion != null && minion.HasDivineShield) { Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", !Game.Logging? "":$"{this} divine shield absorbed incoming damage."); minion.HasDivineShield = false; return(0); } int armor = hero?.Armor ?? 0; int amount = hero == null ? damage : armor < damage ? damage - armor : 0; // added pre damage PreDamage = amount; // Predamage triggers (Ice Block) if (PreDamageTrigger != null) { PreDamageTrigger.Invoke(this); amount = PreDamage; } if (IsImmune) { Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", !Game.Logging ? "" : $"{this} is immune."); PreDamage = 0; return(0); } // remove armor first from hero .... if (armor > 0) { hero.Armor = armor < damage ? 0 : armor - damage; } // final damage is beeing accumulated Damage += amount; Game.Log(LogLevel.INFO, BlockType.ACTION, "Character", !Game.Logging? "":$"{this} took damage for {PreDamage}({damage}). {(fatigue ? "(fatigue)" : "")}"); // reset predamage PreDamage = 0; //LastAffectedBy = source.Id; TODO // Damage event is created // Collect all the tasks and sort them by order of play // Death phase and aura update are not emerge here // place event related data Game.TaskQueue.StartEvent(); EventMetaData temp = Game.CurrentEventData; Game.CurrentEventData = new EventMetaData(source, this, amount); // on-damage triggers TakeDamageTrigger?.Invoke(this); Game.TriggerManager.OnDamageTrigger(this); Game.TriggerManager.OnDealDamageTrigger(source); Game.ProcessTasks(); Game.TaskQueue.EndEvent(); Game.CurrentEventData = temp; if (source.HasLifeSteal && !_lifestealChecker) { if (_history) { Game.PowerHistory.Add(PowerHistoryBuilder.BlockStart(BlockType.TRIGGER, source.Id, source.Card.Id, -1, 0)); // TriggerKeyword=LIFESTEAL } Game.Log(LogLevel.VERBOSE, BlockType.ATTACK, "TakeDamage", !_logging ? "" : $"lifesteal source {source} has damaged target for {amount}."); source.Controller.Hero.TakeHeal(source, amount); if (_history) { Game.PowerHistory.Add(new PowerHistoryBlockEnd()); } if (source.Controller.Hero.ToBeDestroyed && source.Controller.Hero.Health > 0) { source.Controller.Hero.ToBeDestroyed = false; } } if (this is Hero h) { h.IsDamagedThisTurn = true; } return(amount); }
/// <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); }
/// <summary>Process the specified task. /// The game will execute the desired task and all effects coupled either /// directly or indirectly in synchronous manner. /// /// Call <see cref="Controller.Options(bool)"/> on the <see cref="CurrentPlayer"/> /// instance for tasks which are accepted as arguments. /// After this method returns, check <see cref="Controller.Options(bool)"/> /// again until only <see cref="EndTurnTask"/> remains, which will /// start the turn of <see cref="CurrentOpponent"/>. /// </summary> /// <param name="gameTask">The game task to execute.</param> public void Process(PlayerTask gameTask) { // start with no splits ... Splits = new List <Game>(); Log(LogLevel.INFO, BlockType.PLAY, "Game", gameTask.FullPrint()); // clear last power history PowerHistory.Last.Clear(); // make sure that we only use task for this game ... gameTask.Game = this; gameTask.Process(); // add enchantment and buff tag changes if (History) { Enchants.ForEach(p => p.Effects.Keys.ToList().ForEach(t => IdEntityDic.Values.ToList().ForEach(o => PowerHistory.Add(PowerHistoryBuilder.TagChange(o.Id, t, o[t]))))); foreach (var controller in _players) { controller.Hero.Enchants.ForEach(p => p.Effects.Keys.ToList().ForEach(t => PowerHistory.Add(PowerHistoryBuilder.TagChange(Game.CurrentPlayer.Hero.Id, t, Game.CurrentPlayer.Hero[t])))); //CurrentPlayer.Hero.Weapon?.Enchants.ForEach(p => p.IsEnabled()); //CurrentPlayer.Hero.Weapon?.Triggers.ForEach(p => p.IsEnabled()); //CurrentOpponent.Hero.Weapon?.Enchants.ForEach(p => p.IsEnabled()); //CurrentOpponent.Hero.Weapon?.Triggers.ForEach(p => p.IsEnabled()); controller.ControlledZones.Where(z => z != null).ToList().ForEach(z => z.Enchants.ForEach(p => p.Effects.Keys.ToList().ForEach(t => z.GetAll.ForEach(o => PowerHistory.Add(PowerHistoryBuilder.TagChange(o.Id, t, o[t])))))); } Characters.ForEach(c => c.Enchants.ForEach(p => p.Effects.Keys.ToList().ForEach(t => PowerHistory.Add(PowerHistoryBuilder.TagChange(c.Id, t, c[t]))))); } if (Splitting) { var finalSplits = SplitNode.GetSolutions(this, 10, 10000); Dump("Split", $"found {finalSplits.Count} final splits of {finalSplits.Sum(p => p.SameState + 1)}!"); finalSplits.GroupBy(p => p.SameState) .Select(i => new { Word = i.Key, Count = i.Count() }) .ToList().ForEach(p => Dump("Split", $" {p.Count}, with {p.Word} same states")); FinalSplits = finalSplits; } }