public void InitState(GameState gameState)
 {
     levelType.InitState(gameState);
     foreach (KeyValuePair<MinionType, Point> kv in scenery)
     {
         gameState.CreateMinion(kv.Key, false, kv.Value);
     }
     MinionAnimationSequence anim = new MinionAnimationSequence();
     foreach (KeyValuePair<Card, Point> kv in ongoingEffects)
     {
         gameState.PlayCard(kv.Key, null, TriggerItem.create(kv.Value), anim);
     }
 }
 public virtual void ApplyOngoingLateEffects(GameState gameState, MinionAnimationSequence animation)
 {
     gameState.ApplyEffect(type.ongoing_late, new EffectContext(gameState, this, null, animation));
 }
        public override void ApplyOngoingLateEffects(GameState gameState, MinionAnimationSequence animation)
        {
            base.ApplyOngoingLateEffects(gameState, animation);

            TakeDamage(gameState, permanentStats.burning, DamageType.fire, this);
            permanentStats.burning = permanentStats.burningNextTurn;
            permanentStats.burningNextTurn = 0;
        }
        public bool CheckAttacks(GameState gameState, int bonusDamage, MinionAnimationBatch attack, MinionAnimationBatch recover, MinionAnimationSequence animation)
        {
            if (deleted || (stats.attack+bonusDamage) <= 0 || !gameState.CanPayCost(mtype.attackCost))
                return false;

            if (attack.HasAnimation(this))
                return false;

            Point[] attackOffsets = gameState.getOffsetsForRange(stats.range);

            if ((stats.attack+bonusDamage) > 0)
            {
                foreach (Point p in attackOffsets)
                {
                    if (CheckAttack(gameState, bonusDamage, new Point(position.X + p.X, position.Y + p.Y), attack, recover))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        public void ResolveWaitingTriggers(MinionAnimationSequence animation)
        {
            int loopCount = 0;
            while(triggersWaiting.Count > 0)
            {
                loopCount++;
                List<WaitingTrigger> triggersResolving = triggersWaiting;
                triggersWaiting = new List<WaitingTrigger>();

                bool hasAttackTriggers = false;
                foreach(WaitingTrigger trigger in triggersResolving)
                {
                    if (trigger.ability.isAttackTrigger)
                        hasAttackTriggers = true;
                    else
                        trigger.ability.Apply(new EffectContext(this, null, trigger.permanent, TriggerItem.create(trigger.permanent), trigger.evt, animation));
                }

                if (hasAttackTriggers)
                {
                    MinionAnimationBatch attackAnim = animation.AddBatch(new GameState(this), Game1.ATTACK_ANIM_DURATION);
                    MinionAnimationBatch recoverAnim = animation.AddBatch(this, Game1.RECOVER_ANIM_DURATION);
                    foreach (WaitingTrigger trigger in triggersResolving)
                    {
                        if (trigger.ability.isAttackTrigger)
                            trigger.ability.Apply(new EffectContext(this, trigger.permanent, trigger.position, trigger.evt, attackAnim, recoverAnim, animation));
                    }
                    recoverAnim.SetInitialGameState(new GameState(this));
                }

                DeadMinionsDie();

                if (loopCount > 100)
                {
                    triggersWaiting.Clear();
                }
            }
        }
        public void TurnEffects(MinionAnimationSequence animation)
        {
            CleanUp(animation);

            List<Minion> savedMinions = new List<Minion>(minions.Values);
            foreach (Minion p in savedMinions)
            {
                p.ResetTemporaryEffects();
            }

            foreach (Minion p in savedMinions)
            {
                p.ApplyOngoingEffects(this, animation);
            }

            foreach(KeyValuePair<Point, Minion> entry in minions )
            {
                if (!entry.Value.TryPayUpkeep(this))
                {
                    Destroyed(entry.Key, entry.Value);
                }
            }

            MinionsAttack(animation);
            CleanUp(animation);

            MoveEnemies(animation);

            var finalMinions = minions.Values.ToList();
            foreach (Minion p in finalMinions)
            {
                p.ApplyOngoingLateEffects(this, animation);
            }

            CleanUp(animation);

            if (gameEndState == GameEndState.GameRunning && WonLevel())
            {
                gameEndState = GameEndState.GameWon;
            }

            turnNumber++;
        }
        public void PlayCard(Card c, Minion caster, TriggerItem target, MinionAnimationSequence animation)
        {
            PayCost(c.cost);

            HandleTriggers(new TriggerEvent(TriggerType.beforeSpells));
            if(Card.get("wait") != c)
                HandleTriggers(new TriggerEvent(TriggerType.beforeActualSpell, c));

            ApplyCardEffect(c, caster, target, animation);

            HandleTriggers(new TriggerEvent(TriggerType.afterSpells));
            if (c.effect != null || c.ongoingType != null)
                HandleTriggers(new TriggerEvent(TriggerType.afterActualSpell, c));
        }
        public void MoveEnemies(MinionAnimationSequence animation)
        {
            List<MinionMove> minionMoves = new List<MinionMove>();
            HashSet<Minion> minionsStillMoving = new HashSet<Minion>();

            MinionAnimationBatch stepBatch = animation.AddBatch(this, Game1.WALK_ANIM_DURATION);
            // enemies walk forward
            Point levelSize = levelScript.levelSize;
            for (int x = 0; x < levelSize.X; x++) //NB processing these in ascending X order - this matters
            {
                for (int y = levelSize.Y - 1; y >= 0; y--)
                {
                    Minion m = getMinionAt(new Point(x, y));

                    if(m == null)
                        continue;

                    if(m.isEnemy && m.stats.move > 0)
                    {
                        HandleTriggers(new TriggerEvent(TriggerType.beforeMove, m));

                        Vector2 oldDrawPos = m.drawPos;
                        if (m.stats.move == 1 && m.stats.hasKeyword(Keyword.slow) && !m.slow_movedHalfWay)
                        {
                            m.slow_movedHalfWay = true;
                            stepBatch.AddAnimation(m, oldDrawPos, m.drawPos);
                        }
                        else
                        {
                            MinionMove mmove = new MinionMove(m);
                            minionMoves.Add(mmove);
                            minionsStillMoving.Add(m);
                        }
                    }
                }
            }

            CleanUp(animation);

            bool hasMoreMoves = true;
            bool firstPass = true;
            while(hasMoreMoves)
            {
                foreach (MinionMove mmove in minionMoves)
                {
                    if (mmove.movesLeft <= 0)
                        continue;

                    if (levelScript.Blocks(mmove.moveTo, TargetType.empty))
                    {
                        mmove.movesLeft = 0;
                        mmove.moveSpent = true;
                        minionsStillMoving.Remove(mmove.minion);
                    }
                    else if (minions.ContainsKey(mmove.moveTo) && !minionsStillMoving.Contains(getMinionAt(mmove.moveTo)))
                    {
                        // If I'm blocked:
                        if (mmove.minion.stats.hasKeyword(Keyword.unstoppable) || getMinionAt(mmove.moveTo).stats.hasKeyword(Keyword.intangible))
                        {
                            Destroyed(mmove.moveTo, mmove.minion);
                        }
                        mmove.moveSpent = true;
                    }
                }
                CleanUp(animation);

                hasMoreMoves = false;
                foreach (MinionMove mmove in minionMoves)
                {
                    if (mmove.movesLeft > 0)
                    {
                        if (TryMove(mmove, mmove.moveTo))
                        {
                            mmove.moveSpent = true;
                            mmove.minion.slow_movedHalfWay = false;
                            stepBatch.AddAnimation(mmove.minion, mmove.currentAnimPos, mmove.minion.drawPos);
                            mmove.currentAnimPos = mmove.minion.drawPos;
                        }

                        if (mmove.moveSpent)
                        {
                            mmove.movesLeft--;
                            mmove.moveSpent = false;
                        }

                        if (mmove.movesLeft > 0)
                        {
                            hasMoreMoves = true;
                        }
                        else
                        {
                            minionsStillMoving.Remove(mmove.minion);
                        }
                    }
                }

                if (firstPass)
                {
                    levelScript.Apply(this, stepBatch);
                    firstPass = false;
                }
                stepBatch.SetInitialGameState(new GameState(this));

                stepBatch = animation.AddBatch(this, Game1.WALK_ANIM_DURATION);
            }
        }
        public void MinionsAttack(MinionAnimationSequence animation)
        {
            HandleTriggers(new TriggerEvent(TriggerType.beforeCombat));
            CleanUp(animation);

            MinionAnimationBatch attack = null;
            MinionAnimationBatch recover = null;
            if (animation != null)
            {
                attack = animation.AddBatch(new GameState(this), Game1.ATTACK_ANIM_DURATION);
                recover = animation.AddBatch(this, Game1.RECOVER_ANIM_DURATION);
            }

            for (int y = levelScript.levelSize.Y - 1; y >= 0; y--)
            {
                for (int x = 0; x < levelScript.levelSize.X; x++)
                {
                    Minion p = getMinionAt(new Point(x, y));
                    if (p != null)
                    {
                        p.CheckAttacks(this, 0, attack, recover, animation);
                    }
                }
            }

            recover.SetInitialGameState(new GameState(this));

            HandleTriggers(new TriggerEvent(TriggerType.afterCombat));
            CleanUp(animation);
        }
 public void CleanUp(MinionAnimationSequence animation)
 {
     DeadMinionsDie();
     ResolveWaitingTriggers(animation);
 }
        public void ApplyCardEffect(Card c, Minion caster, TriggerItem target, MinionAnimationSequence animation)
        {
            TextChanges changes = null;
            if (cardTextChanges.ContainsKey(c))
                changes = cardTextChanges[c];

            ApplyEffect(c.effect, new EffectContext(this, changes, caster, target, new TriggerEvent(TriggerType.onSpell, caster, target.permanent), animation));

            if (c.ongoingType != null)
            {
                Point pos = target.position;
                ongoingEffects[pos] = new Ongoing(c, pos);
            }
        }