void instance_zulaman::DoTimeRunSay(RunEventSteps uiData)
{
    switch (uiData)
    {
        case RUN_START:     DoOrSimulateScriptTextForThisInstance(SAY_INST_BEGIN, NPC_MALACRASS); break;
        case RUN_FAIL:      DoOrSimulateScriptTextForThisInstance(urand(0, 1) ? SAY_INST_SACRIF1 : SAY_INST_SACRIF2, NPC_MALACRASS); break;
        case RUN_DONE:      DoOrSimulateScriptTextForThisInstance(SAY_INST_COMPLETE, NPC_MALACRASS); break;
        case RUN_PROGRESS:
            // This function is on progress called before the data is set to the array
            switch (GetKilledPreBosses() + 1)
            {
                case 1:     DoOrSimulateScriptTextForThisInstance(SAY_INST_PROGRESS_1, NPC_MALACRASS); break;
                case 2:     DoOrSimulateScriptTextForThisInstance(SAY_INST_PROGRESS_2, NPC_MALACRASS); break;
                case 3:     DoOrSimulateScriptTextForThisInstance(SAY_INST_PROGRESS_3, NPC_MALACRASS); break;
            }
            break;
        case RUN_FAIL_SOON:
            switch (GetKilledPreBosses())
            {
                case 0:     DoOrSimulateScriptTextForThisInstance(SAY_INST_WARN_1, NPC_MALACRASS); break;
                case 1:     DoOrSimulateScriptTextForThisInstance(SAY_INST_WARN_2, NPC_MALACRASS); break;
                case 2:     DoOrSimulateScriptTextForThisInstance(SAY_INST_WARN_3, NPC_MALACRASS); break;
                case 3:     DoOrSimulateScriptTextForThisInstance(SAY_INST_WARN_4, NPC_MALACRASS); break;
            }
            break;
    }
}
void instance_naxxramas::DoTaunt()
{
    if (m_auiEncounter[TYPE_KELTHUZAD] != DONE)
    {
        uint8 uiWingsCleared = 0;

        if (m_auiEncounter[TYPE_MAEXXNA] == DONE)
            ++uiWingsCleared;

        if (m_auiEncounter[TYPE_LOATHEB] == DONE)
            ++uiWingsCleared;

        if (m_auiEncounter[TYPE_FOUR_HORSEMEN] == DONE)
            ++uiWingsCleared;

        if (m_auiEncounter[TYPE_THADDIUS] == DONE)
            ++uiWingsCleared;

        switch(uiWingsCleared)
        {
            case 1: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT1, NPC_KELTHUZAD); break;
            case 2: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT2, NPC_KELTHUZAD); break;
            case 3: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT3, NPC_KELTHUZAD); break;
            case 4: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT4, NPC_KELTHUZAD); break;
        }
    }
}
void instance_sunwell_plateau::Update(uint32 uiDiff)
{
    DialogueUpdate(uiDiff);

    if (m_uiKalecRespawnTimer)
    {
        if (m_uiKalecRespawnTimer <= uiDiff)
        {
            if (Creature* pKalecDragon = GetSingleCreatureFromStorage(NPC_KALECGOS_DRAGON))
                pKalecDragon->Respawn();
            if (Creature* pKalecHuman = GetSingleCreatureFromStorage(NPC_KALECGOS_HUMAN))
                pKalecHuman->Respawn();
            m_uiKalecRespawnTimer = 0;
        }
        else
            m_uiKalecRespawnTimer -= uiDiff;
    }

    // Muru berserk timer; needs to be done here because it involves two distinct creatures
    if (m_auiEncounter[TYPE_MURU] == IN_PROGRESS)
    {
        if (m_uiMuruBerserkTimer < uiDiff)
        {
            if (Creature* pEntrpius = GetSingleCreatureFromStorage(NPC_ENTROPIUS, true))
                pEntrpius->CastSpell(pEntrpius, SPELL_MURU_BERSERK, true);
            else if (Creature* pMuru = GetSingleCreatureFromStorage(NPC_MURU))
                pMuru->CastSpell(pMuru, SPELL_MURU_BERSERK, true);

            m_uiMuruBerserkTimer = 10 * MINUTE * IN_MILLISECONDS;
        }
        else
            m_uiMuruBerserkTimer -= uiDiff;
    }

    if (m_auiEncounter[TYPE_KILJAEDEN] == NOT_STARTED || m_auiEncounter[TYPE_KILJAEDEN] == FAIL)
    {
        if (m_uiKiljaedenYellTimer < uiDiff)
        {
            switch (urand(0, 4))
            {
                case 0: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_1, NPC_KILJAEDEN_CONTROLLER); break;
                case 1: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_2, NPC_KILJAEDEN_CONTROLLER); break;
                case 2: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_3, NPC_KILJAEDEN_CONTROLLER); break;
                case 3: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_4, NPC_KILJAEDEN_CONTROLLER); break;
                case 4: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_5, NPC_KILJAEDEN_CONTROLLER); break;
            }
            m_uiKiljaedenYellTimer = 90000;
        }
        else
            m_uiKiljaedenYellTimer -= uiDiff;
    }
}
void instance_zulgurub::DoYellAtTriggerIfCan(uint32 uiTriggerId)
{
    if (uiTriggerId == AREATRIGGER_ENTER && !m_bHasIntroYelled)
    {
        DoOrSimulateScriptTextForThisInstance(SAY_HAKKAR_PROTECT, NPC_HAKKAR);
        m_bHasIntroYelled = true;
    }
    else if (uiTriggerId == AREATRIGGER_ALTAR && !m_bHasAltarYelled)
    {
        DoOrSimulateScriptTextForThisInstance(SAY_MINION_DESTROY, NPC_HAKKAR);
        m_bHasAltarYelled = true;
    }
}
void instance_stratholme::ThazudinAcolyteJustDied(Creature* pCreature)
{
    for (uint8 i = 0; i < MAX_ZIGGURATS; ++i)
    {
        if (m_zigguratStorage[i].m_lZigguratAcolyteGuid.empty())
            continue;                               // nothing to do anymore for this ziggurat

        m_zigguratStorage[i].m_lZigguratAcolyteGuid.remove(pCreature->GetObjectGuid());
        if (m_zigguratStorage[i].m_lZigguratAcolyteGuid.empty())
        {
            // A random zone yell after one is cleared
            int32 aAnnounceSay[MAX_ZIGGURATS] = {SAY_ANNOUNCE_ZIGGURAT_1, SAY_ANNOUNCE_ZIGGURAT_2, SAY_ANNOUNCE_ZIGGURAT_3};
            DoOrSimulateScriptTextForThisInstance(aAnnounceSay[i], NPC_THUZADIN_ACOLYTE);

            // Kill Crystal
            if (Creature* pCrystal = instance->GetCreature(m_zigguratStorage[i].m_crystalGuid))
                pCrystal->DealDamage(pCrystal, pCrystal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);

            switch (i)
            {
                case 0: SetData(TYPE_BARONESS, SPECIAL); break;
                case 1: SetData(TYPE_NERUB, SPECIAL);    break;
                case 2: SetData(TYPE_PALLID, SPECIAL);   break;
            }
        }
    }
}
void instance_ulduar::JustDidDialogueStep(int32 iEntry)
{
    switch (iEntry)
    {
        case SAY_PRE_LEVIATHAN_1:
        case SAY_PRE_LEVIATHAN_2:
        case SAY_PRE_LEVIATHAN_3:
            DoOrSimulateScriptTextForThisInstance(iEntry, NPC_BRONZEBEARD_RADIO);
            break;
        case NPC_LEVIATHAN:
            // move the leviathan in the arena
            if (Creature* pLeviathan = GetSingleCreatureFromStorage(NPC_LEVIATHAN))
            {
                // the boss has increased speed for this move; handled as custom
                float fSpeedRate = pLeviathan->GetSpeedRate(MOVE_RUN);
                pLeviathan->SetWalk(false);
                pLeviathan->SetSpeedRate(MOVE_RUN, 5);
                pLeviathan->GetMotionMaster()->MovePoint(1, afLeviathanMovePos[0], afLeviathanMovePos[1], afLeviathanMovePos[2]);
                pLeviathan->SetSpeedRate(MOVE_RUN, fSpeedRate);

                // modify respawn / home position to the center of arena
                pLeviathan->SetRespawnCoord(afLeviathanMovePos[0], afLeviathanMovePos[1], afLeviathanMovePos[2], afLeviathanMovePos[3]);
            }

            // Note: starting 4.x this gate is a GO 33 and it's destroyed at this point
            DoUseDoorOrButton(GO_LEVIATHAN_GATE);
            break;
    }
}
// Function that spawns next scourge wave
void instance_culling_of_stratholme::DoSpawnNextScourgeWave()
{
    Creature* pSummoner = GetSingleCreatureFromStorage(NPC_ARTHAS);
    if (!pSummoner)
        return;

    DoOrSimulateScriptTextForThisInstance(m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_iYellId, NPC_LORDAERON_CRIER);

    for (uint8 i = 0; i < MAX_SCOURGE_TYPE_PER_WAVE; ++i)
    {
        // get the mob entry
        uint32 uiEntry = GetRandomMobOfType(uiScourgeWaveDef[m_uiScourgeWaveCount - 1][i]);
        if (!uiEntry)
            continue;

        float fX, fY, fZ, fO;
        fO = m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fO;

        // bosses get exact location
        if (uiScourgeWaveDef[m_uiScourgeWaveCount - 1][i] == SCOURGE_TYPE_BOSS || uiScourgeWaveDef[m_uiScourgeWaveCount - 1][i] == SCOURGE_TYPE_ACOLYTES)
        {
            fX = m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fX;
            fY = m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fY;
            fZ = m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fZ;
        }
        // random position around point
        else
            pSummoner->GetRandomPoint(m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fX, m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fY, m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fZ, 5.0f, fX, fY, fZ);

        // special requirement for acolytes - spawn a pack of 4
        if (uiScourgeWaveDef[m_uiScourgeWaveCount - 1][i] == SCOURGE_TYPE_ACOLYTES)
        {
            for (uint8 j = 0; j < 4; ++j)
            {
                pSummoner->GetRandomPoint(m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fX, m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fY, m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fZ, 5.0f, fX, fY, fZ);
                pSummoner->SummonCreature(uiEntry, fX, fY, fZ, fO, TEMPSUMMON_DEAD_DESPAWN, 0);
            }
        }
        // spawn the selected mob
        else
            pSummoner->SummonCreature(uiEntry, fX, fY, fZ, fO, TEMPSUMMON_DEAD_DESPAWN, 0);
    }

    // start infinite curruptor event on the first wave
    if (m_uiScourgeWaveCount == 1 && !instance->IsRegularDifficulty() && GetData(TYPE_INFINITE_CORRUPTER) != DONE)
        SetData(TYPE_INFINITE_CORRUPTER, IN_PROGRESS);

    // get a random position that is different from the previous one for the next round
    uint8 uiCurrentPos = urand(POS_FESTIVAL_LANE, POS_ELDERS_SQUARE);

    while (uiCurrentPos == m_uiCurrentUndeadPos)
        uiCurrentPos = urand(POS_FESTIVAL_LANE, POS_ELDERS_SQUARE);

    m_uiCurrentUndeadPos = uiCurrentPos;
}
void instance_ruins_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData)
{
    switch (uiType)
    {
        case TYPE_KURINNAXX:
            if (uiData == DONE)
            {
                DoSapwnAndorovIfCan();

                // Yell after kurinnaxx
                DoOrSimulateScriptTextForThisInstance(SAY_OSSIRIAN_INTRO, NPC_OSSIRIAN);
            }
            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_RAJAXX:
            m_auiEncounter[uiType] = uiData;
            if (uiData == IN_PROGRESS)
            {
                DoSortArmyWaves();
            }
            if (uiData == DONE)
            {
                if (Creature* pAndorov = GetSingleCreatureFromStorage(NPC_GENERAL_ANDOROV))
                {
                    if (pAndorov->IsAlive())
                    {
                        pAndorov->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
                    }
                }
            }
            break;
        case TYPE_MOAM:
        case TYPE_BURU:
        case TYPE_AYAMISS:
        case TYPE_OSSIRIAN:
            m_auiEncounter[uiType] = uiData;
            break;
    }

    if (uiData == DONE)
    {
        OUT_SAVE_INST_DATA;

        std::ostringstream saveStream;
        saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]
                   << " " << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5];

        m_strInstData = saveStream.str();

        SaveToDB();
        OUT_SAVE_INST_DATA_COMPLETE;
    }
}
bool instance_stratholme::StartSlaugtherSquare()
{
    if (m_auiEncounter[TYPE_BARONESS] == SPECIAL && m_auiEncounter[TYPE_NERUB] == SPECIAL && m_auiEncounter[TYPE_PALLID] == SPECIAL)
    {
        DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RIVENDARE, NPC_BARON);

        DoUseDoorOrButton(GO_PORT_GAUNTLET);
        DoUseDoorOrButton(GO_PORT_SLAUGTHER);

        debug_log("SD2: Instance Stratholme: Open slaugther square.");

        return true;
    }

    return false;
}
void instance_magtheridons_lair::Update(uint32 uiDiff)
{
    // Prepare to release Magtheridon
    if (m_uiCageBreakTimer)
    {
        if (m_uiCageBreakTimer <= uiDiff)
        {
            switch (m_uiCageBreakStage)
            {
                case 0:
                    if (Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON))
                    {
                        if (pMagtheridon->isAlive())
                        {
                            DoScriptText(EMOTE_NEARLY_FREE, pMagtheridon);
                            m_uiCageBreakTimer = MINUTE * IN_MILLISECONDS;
                        }
                    }
                    break;
                case 1:
                    SetData(TYPE_MAGTHERIDON_EVENT, IN_PROGRESS);
                    m_uiCageBreakTimer = 0;
                    break;
            }

            ++m_uiCageBreakStage;
        }
        else
            m_uiCageBreakTimer -= uiDiff;
    }

    // no yell if event is in progress or finished
    if (m_auiEncounter[TYPE_CHANNELER_EVENT] == IN_PROGRESS || m_auiEncounter[TYPE_MAGTHERIDON_EVENT] == DONE)
        return;

    if (m_uiRandYellTimer < uiDiff)
    {
        DoOrSimulateScriptTextForThisInstance(aRandomTaunt[urand(0, 5)], NPC_MAGTHERIDON);
        m_uiRandYellTimer = 90000;
    }
    else
        m_uiRandYellTimer -= uiDiff;
}
void instance_shattered_halls::Update(uint32 uiDiff)
{
    if (m_auiEncounter[TYPE_EXECUTION] != IN_PROGRESS)
        return;

    if (m_uiExecutionTimer < uiDiff)
    {
        switch (m_uiExecutionStage)
        {
            case 0:
                // Kill the officer
                if (Creature* pSoldier = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? NPC_OFFICER_ALLIANCE : NPC_OFFICER_HORDE))
                    pSoldier->DealDamage(pSoldier, pSoldier->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);

                // Make Kargath yell
                DoOrSimulateScriptTextForThisInstance(m_uiTeam == ALLIANCE ? SAY_KARGATH_EXECUTE_ALLY : SAY_KARGATH_EXECUTE_HORDE, NPC_KARGATH_BLADEFIST);

                // Set timer for the next execution
                DoCastGroupDebuff(SPELL_KARGATH_EXECUTIONER_2);
                m_uiExecutionTimer = 10 * MINUTE * IN_MILLISECONDS;
                break;
            case 1:
                if (Creature* pSoldier = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? NPC_SOLDIER_ALLIANCE_2 : NPC_SOLDIER_HORDE_2))
                    pSoldier->DealDamage(pSoldier, pSoldier->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);

                DoCastGroupDebuff(SPELL_KARGATH_EXECUTIONER_3);
                m_uiExecutionTimer = 15 * MINUTE * IN_MILLISECONDS;
                break;
            case 2:
                if (Creature* pSoldier = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? NPC_SOLDIER_ALLIANCE_3 : NPC_SOLDIER_HORDE_3))
                    pSoldier->DealDamage(pSoldier, pSoldier->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);

                SetData(TYPE_EXECUTION, FAIL);
                m_uiExecutionTimer = 0;
                break;
        }
        ++m_uiExecutionStage;
    }
    else
        m_uiExecutionTimer -= uiDiff;
}
void instance_ruins_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData)
{
    switch (uiType)
    {
    case TYPE_KURINNAXX:
        if (uiData == DONE)
        {
            DoSapwnAndorovIfCan();

            // Yell after kurinnaxx
            DoOrSimulateScriptTextForThisInstance(SAY_OSSIRIAN_INTRO, NPC_OSSIRIAN);
        }
        m_auiEncounter[uiType] = uiData;
        break;
    case TYPE_RAJAXX:
    case TYPE_MOAM:
    case TYPE_BURU:
    case TYPE_AYAMISS:
    case TYPE_OSSIRIAN:
        m_auiEncounter[uiType] = uiData;
        break;
    }

    if (uiData == DONE)
    {
        OUT_SAVE_INST_DATA;

        std::ostringstream saveStream;
        saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]
                   << " " << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5];

        m_strInstData = saveStream.str();

        SaveToDB();
        OUT_SAVE_INST_DATA_COMPLETE;
    }
}
void instance_naxxramas::OnCreatureDeath(Creature* pCreature)
{
    if (pCreature->GetEntry() == NPC_MR_BIGGLESWORTH && m_auiEncounter[TYPE_KELTHUZAD] != DONE)
        DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_CAT_DIED, NPC_KELTHUZAD);
}
void instance_culling_of_stratholme::Update(uint32 uiDiff)
{
    // 25min Run - decrease time, update worldstate every ~20s
    // as the time is always saved by m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME], there is no need for an extra timer
    if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME])
    {
        if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] <= uiDiff)
            SetData(TYPE_INFINITE_CORRUPTER, FAIL);
        else
        {
            m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] -= uiDiff;
            if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] / IN_MILLISECONDS % 20 == 0)
                SetData(TYPE_INFINITE_CORRUPTER_TIME, m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME]);
        }

        // This part is needed for a small "hurry up guys" note, TODO, verify 20min
        if (m_auiEncounter[TYPE_INFINITE_CORRUPTER] == IN_PROGRESS && m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] <= 24 * MINUTE * IN_MILLISECONDS)
            SetData(TYPE_INFINITE_CORRUPTER, SPECIAL);
    }

    // Small Timer, to remove Grain-Crate WorldState and Spawn Second Chromie
    if (m_uiRemoveCrateStateTimer)
    {
        if (m_uiRemoveCrateStateTimer <= uiDiff)
        {
            if (Player* pPlayer = GetPlayerInMap())
                DoSpawnChromieIfNeeded(pPlayer);

            DoUpdateWorldState(WORLD_STATE_CRATES, 0);
            DoChromieWhisper(WHISPER_CHROMIE_CRATES);
            m_uiRemoveCrateStateTimer = 0;
        }
        else
            m_uiRemoveCrateStateTimer -= uiDiff;
    }

    // Respawn Arthas after some time
    if (m_uiArthasRespawnTimer)
    {
        if (m_uiArthasRespawnTimer <= uiDiff)
        {
            if (Player* pPlayer = GetPlayerInMap())
                DoSpawnArthasIfNeeded(pPlayer);

            m_uiArthasRespawnTimer = 0;
        }
        else
            m_uiArthasRespawnTimer -= uiDiff;
    }

    // Handle undead waves
    if (m_uiScourgeWaveTimer)
    {
        if (m_uiScourgeWaveTimer <= uiDiff)
        {
            if (GetData(TYPE_SALRAMM_EVENT) == DONE)
            {
                DoOrSimulateScriptTextForThisInstance(SAY_MEET_TOWN_HALL, NPC_ARTHAS);
                DoUpdateWorldState(WORLD_STATE_WAVE, 0);    // Remove WaveCounter

                // despawn and respawn Arthas in the new location
                if (Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS))
                    pArthas->ForcedDespawn();
                if (Player* pPlayer = GetPlayerInMap())
                    DoSpawnArthasIfNeeded(pPlayer);
            }
            else
            {
                ++m_uiScourgeWaveCount;
                DoUpdateWorldState(WORLD_STATE_WAVE, m_uiScourgeWaveCount);
                DoSpawnNextScourgeWave();
            }

            m_uiScourgeWaveTimer = 0;
        }
        else
            m_uiScourgeWaveTimer -= uiDiff;
    }
}
void instance_ruins_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData)
{
    switch(uiType)
    {
        case TYPE_KURINNAXX:
            if (uiData == DONE)
            {
                DoSapwnAndorovIfCan();

                // Yell after kurinnaxx
                if (m_auiEncounter[uiType] != DONE)
				    DoOrSimulateScriptTextForThisInstance(YELL_OSSIRIAN_BREACHED, NPC_OSSIRIAN);
            }
            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_RAJAXX:
            m_auiEncounter[uiType] = uiData;
            if (uiData == IN_PROGRESS)
            {
                m_hasResetRajaxx = false;
                DoSortArmyWaves();
            }
            if (uiData == DONE)
            {
                Map::PlayerList const &PlayerList = instance->GetPlayers();
                for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr)
                {
                    if (itr->getSource() && itr->getSource()->IsInWorld())
                        itr->getSource()->SetCombatTimer(0);
                }

                if (Creature* pAndorov = GetSingleCreatureFromStorage(NPC_GENERAL_ANDOROV))
                {
                    if (pAndorov->isAlive() && m_auiEncounter[TYPE_ANDOROV] != FAIL)
                    {
#if AQ_PATCH >= 10
                        pAndorov->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
#else
                        pAndorov->ForcedDespawn();
#endif
                        Map::PlayerList const& lPlayers = this->instance->GetPlayers();
                        
                        if (!lPlayers.isEmpty())
                            for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr)
                            {
                                if (Player* pPlayer = itr->getSource())
                                    pPlayer->RewardReputation(609, 150);
                            }
                    }
                }
            }
            break;
        case TYPE_MOAM:
        case TYPE_BURU:
        case TYPE_AYAMISS:
        case TYPE_OSSIRIAN:
        case TYPE_ANDOROV:
            m_auiEncounter[uiType] = uiData;
            break;
    }

    if (uiData == DONE || (uiType == TYPE_RAJAXX && uiData == IN_PROGRESS) || (uiType == TYPE_ANDOROV && uiData == FAIL))
    {
        OUT_SAVE_INST_DATA;

        std::ostringstream saveStream;
        saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]
            << " " << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]
            << " " << m_auiEncounter[6];

        m_strInstData = saveStream.str();

        SaveToDB();
        OUT_SAVE_INST_DATA_COMPLETE;
    }
}
void instance_culling_of_stratholme::SetData(uint32 uiType, uint32 uiData)
{
    switch (uiType)
    {
        case TYPE_GRAIN_EVENT:
            m_auiEncounter[uiType] = uiData;
            if (uiData == SPECIAL)
                DoUpdateWorldState(WORLD_STATE_CRATES, 1);
            else if (uiData == IN_PROGRESS)
            {
                // safety check
                if (m_uiGrainCrateCount >= MAX_GRAIN_CRATES)
                    return;

                ++m_uiGrainCrateCount;
                DoUpdateWorldState(WORLD_STATE_CRATES_COUNT, m_uiGrainCrateCount);

                if (m_uiGrainCrateCount == MAX_GRAIN_CRATES)
                {
                    m_uiRemoveCrateStateTimer = 20000;
                    SetData(TYPE_GRAIN_EVENT, DONE);
                }
            }
            break;
        case TYPE_ARTHAS_INTRO_EVENT:
            m_auiEncounter[uiType] = uiData;
            if (uiData == DONE)
            {
                m_uiScourgeWaveCount = 0;
                m_uiScourgeWaveTimer = 1000;
                DoUpdateZombieResidents();

                SetData(TYPE_MEATHOOK_EVENT, IN_PROGRESS);
            }
            break;
        case TYPE_MEATHOOK_EVENT:
            m_auiEncounter[uiType] = uiData;
            if (uiData == DONE)
            {
                m_uiScourgeWaveTimer = 20000;
                SetData(TYPE_SALRAMM_EVENT, IN_PROGRESS);
            }
            break;
        case TYPE_SALRAMM_EVENT:
            m_auiEncounter[uiType] = uiData;
            if (uiData == DONE)
                m_uiScourgeWaveTimer = 5000;
            break;
        case TYPE_ARTHAS_TOWNHALL_EVENT:
            m_auiEncounter[uiType] = uiData;
            if (uiData == DONE)
            {
                // despawn arthas and spawn him in the next point
                if (Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS))
                    pArthas->ForcedDespawn();

                if (Player* pPlayer = GetPlayerInMap())
                    DoSpawnArthasIfNeeded(pPlayer);
            }
            break;
        case TYPE_EPOCH_EVENT:
            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_ARTHAS_ESCORT_EVENT:
            // use fail in order to respawn Arthas
            if (uiData == FAIL)
            {
                m_uiArthasRespawnTimer = 10000;

                // despawn the bosses if Arthas dies in order to avoid exploits
                if (Creature* pEpoch = GetSingleCreatureFromStorage(NPC_LORD_EPOCH, true))
                    pEpoch->ForcedDespawn();
                if (Creature* pMalganis = GetSingleCreatureFromStorage(NPC_MALGANIS, true))
                    pMalganis->ForcedDespawn();
            }
            else
                m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_MALGANIS_EVENT:
            m_auiEncounter[uiType] = uiData;
            if (uiData == DONE)
            {
                DoUseDoorOrButton(GO_CITY_ENTRANCE_GATE);
                DoToggleGameObjectFlags(instance->IsRegularDifficulty() ? GO_DARK_RUNED_CHEST : GO_DARK_RUNED_CHEST_H, GO_FLAG_NO_INTERACT, false);
                DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_DARK_RUNED_CHEST : GO_DARK_RUNED_CHEST_H, 30 * MINUTE);

                if (Player* pPlayer = GetPlayerInMap())
                    DoSpawnChromieIfNeeded(pPlayer);
            }
            break;
        case TYPE_INFINITE_CORRUPTER_TIME:
            m_auiEncounter[uiType] = uiData;
            if (!uiData)
            {
                DoUpdateWorldState(WORLD_STATE_TIME, 0);    // Remove Timer
                DoUpdateWorldState(WORLD_STATE_TIME_COUNTER, 0);
            }
            else
                DoUpdateWorldState(WORLD_STATE_TIME_COUNTER, uiData / (MINUTE * IN_MILLISECONDS));
            break;
        case TYPE_INFINITE_CORRUPTER:
            m_auiEncounter[uiType] = uiData;
            switch (uiData)
            {
                case IN_PROGRESS:
                    if (!GetData(TYPE_INFINITE_CORRUPTER_TIME))
                    {
                        SetData(TYPE_INFINITE_CORRUPTER_TIME, MINUTE * 25 * IN_MILLISECONDS);
                        DoUpdateWorldState(WORLD_STATE_TIME, 1);
                        DoChromieWhisper(WHISPER_CHROMIE_GUARDIAN);

                        // spawn the corruptor for the first time
                        if (Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS))
                            DoSpawnCorruptorIfNeeded(pArthas);
                    }
                    break;
                case DONE:
                    // event completed - epilog handled by dbscript
                    SetData(TYPE_INFINITE_CORRUPTER_TIME, 0);
                    break;
                case SPECIAL:
                    DoChromieWhisper(WHISPER_CHROMIE_HURRY);
                    break;
                case FAIL:
                    // event failed - despawn the corruptor
                    SetData(TYPE_INFINITE_CORRUPTER_TIME, 0);
                    if (Creature* pCorrupter = GetSingleCreatureFromStorage(NPC_INFINITE_CORRUPTER))
                    {
                        DoOrSimulateScriptTextForThisInstance(SAY_CORRUPTOR_DESPAWN, NPC_INFINITE_CORRUPTER);

                        if (pCorrupter->isAlive())
                            pCorrupter->ForcedDespawn();
                    }
                    break;
            }
            break;
    }

    if (uiData == DONE || uiType == TYPE_INFINITE_CORRUPTER_TIME)
    {
        OUT_SAVE_INST_DATA;

        std::ostringstream saveStream;
        saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " "
                   << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " "
                   << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " "
                   << m_auiEncounter[9];

        m_strInstData = saveStream.str();

        SaveToDB();
        OUT_SAVE_INST_DATA_COMPLETE;
    }
}
void instance_stratholme::Update(uint32 uiDiff)
{
    if (m_uiBarthilasRunTimer)
    {
        if (m_uiBarthilasRunTimer <= uiDiff)
        {
            Creature* pBarthilas = GetSingleCreatureFromStorage(NPC_BARTHILAS);
            if (pBarthilas && pBarthilas->isAlive() && !pBarthilas->isInCombat())
                pBarthilas->NearTeleportTo(aStratholmeLocation[1].m_fX, aStratholmeLocation[1].m_fY, aStratholmeLocation[1].m_fZ, aStratholmeLocation[1].m_fO);

            SetData(TYPE_BARTHILAS_RUN, DONE);
            m_uiBarthilasRunTimer = 0;
        }
        else
            m_uiBarthilasRunTimer -= uiDiff;
    }

    // Timer to summon Aurius into the Slaughter House once Baron is engaged
    if (m_uiAuriusSummonTimer)
    {
        if (m_uiAuriusSummonTimer <= uiDiff)
        {
            SetData(TYPE_AURIUS, IN_PROGRESS);
            m_uiAuriusSummonTimer = 0;
        }
        else
            m_uiAuriusSummonTimer -= uiDiff;
    }

    // Check changes for Baron ultimatum timer only if Baron is not already in combat
    if (m_uiBaronRunTimer && GetData(TYPE_BARON) != IN_PROGRESS)
    {
        if (m_uiYellCounter == 0 && m_uiBaronRunTimer <= 10 * MINUTE * IN_MILLISECONDS)
        {
            DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_10_MIN, NPC_BARON);
            ++m_uiYellCounter;
        }
        else if (m_uiYellCounter == 1 && m_uiBaronRunTimer <= 5 * MINUTE * IN_MILLISECONDS)
        {
            DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_5_MIN, NPC_BARON);
            ++m_uiYellCounter;
        }
        // Used to create a delay of 10s between Baron speech and Ysida's answer
        else if (m_uiYellCounter == 2 && m_uiBaronRunTimer <= (5 * MINUTE - 10) * IN_MILLISECONDS)
        {
            DoOrSimulateScriptTextForThisInstance(YSIDA_SAY_RUN_5_MIN, NPC_YSIDA);
            ++m_uiYellCounter;
        }

        if (m_uiBaronRunTimer <= uiDiff)
        {
            if (GetData(TYPE_BARON_RUN) != FAIL)
            {
                SetData(TYPE_BARON_RUN, FAIL);

                // Open the cage and let Ysida face her doom
                if (Creature* pYsida = GetSingleCreatureFromStorage(NPC_YSIDA))
                {
                    pYsida->GetMotionMaster()->MovePoint(0, aStratholmeLocation[8].m_fX, aStratholmeLocation[8].m_fY, aStratholmeLocation[8].m_fZ, aStratholmeLocation[8].m_fO);
                    DoUseDoorOrButton(GO_YSIDA_CAGE);
                }

                DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_FAIL, NPC_BARON);

                m_uiBaronRunTimer = 8000;  // We reset the timer so the speech of Ysida is not said at the same time than the Baron's one
            }
            else
            {
                // Baron ultimatum failed: let the Baron kill her
                if (Creature* pYsida = GetSingleCreatureFromStorage(NPC_YSIDA))
                    if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                        pBaron->CastSpell(pYsida, SPELL_BARON_SOUL_DRAIN, true);

                DoOrSimulateScriptTextForThisInstance(YSIDA_SAY_RUN_FAIL, NPC_YSIDA);

                m_uiBaronRunTimer = 0;  // event done for good, no more speech
                debug_log("SD2: Instance Stratholme: Baron run event reached end. Event has state %u.", GetData(TYPE_BARON_RUN));
            }
        }
        else
            m_uiBaronRunTimer -= uiDiff;
    }

    if (m_uiMindlessSummonTimer)
    {
        if (m_uiMindlessCount < 30)
        {
            if (m_uiMindlessSummonTimer <= uiDiff)
            {
                if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                {
                    // Summon mindless skeletons and move them to random point in the center of the square
                    if (Creature* pTemp = pBaron->SummonCreature(NPC_MINDLESS_UNDEAD, aStratholmeLocation[4].m_fX, aStratholmeLocation[4].m_fY, aStratholmeLocation[4].m_fZ, aStratholmeLocation[4].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0))
                    {
                        float fX, fY, fZ;
                        pBaron->GetRandomPoint(aStratholmeLocation[5].m_fX, aStratholmeLocation[5].m_fY, aStratholmeLocation[5].m_fZ, 20.0f, fX, fY, fZ);
                        pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ);
                        m_luiUndeadGUIDs.push_back(pTemp->GetObjectGuid());
                        ++m_uiMindlessCount;
                    }
                }
                m_uiMindlessSummonTimer = 400;
            }
            else
                m_uiMindlessSummonTimer -= uiDiff;
        }
        else
            m_uiMindlessSummonTimer = 0;
    }

    if (m_uiSlaugtherSquareTimer)
    {
        if (m_uiSlaugtherSquareTimer <= uiDiff)
        {
            // Call next Abomnations
            for (GuidSet::const_iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end(); ++itr)
            {
                Creature* pAbom = instance->GetCreature(*itr);
                // Skip killed and already walking Abomnations
                if (!pAbom || !pAbom->isAlive() || pAbom->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
                    continue;

                // Let Move to somewhere in the middle
                if (!pAbom->isInCombat())
                {
                    if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_PORT_SLAUGTHER))
                    {
                        float fX, fY, fZ;
                        pAbom->GetRandomPoint(pDoor->GetPositionX(), pDoor->GetPositionY(), pDoor->GetPositionZ(), 10.0f, fX, fY, fZ);
                        pAbom->GetMotionMaster()->MovePoint(0, fX, fY, fZ);
                    }
                }
                break;
            }

            // TODO - how fast are they called?
            m_uiSlaugtherSquareTimer = urand(15000, 30000);
        }
        else
            m_uiSlaugtherSquareTimer -= uiDiff;
    }
}
void instance_blackwing_lair::Update(uint32 uiDiff)
{
    // Scepter of the Shifting Sand epic quest line
    if (m_uiScepterEpicTimer)
    {
        if (m_uiScepterEpicTimer <= uiDiff)
        {
            switch (m_uiScepterQuestStep)
            {
                case 0:     // On quest acceptance
                    DoOrSimulateScriptTextForThisInstance(YELL_REDSHARD_TAUNT_1, NPC_LORD_VICTOR_NEFARIUS);
                    m_uiScepterEpicTimer = 2 * HOUR * IN_MILLISECONDS;
                    break;
                case 1:     // 2 hours time mark
                    switch (urand(0, 1))
                    {
                        case 0:
                            DoOrSimulateScriptTextForThisInstance(YELL_REDSHARD_TAUNT_2, NPC_LORD_VICTOR_NEFARIUS);
                            DoOrSimulateScriptTextForThisInstance(EMOTE_REDSHARD_TAUNT_1, NPC_LORD_VICTOR_NEFARIUS);
                            break;
                        case 1:
                            DoOrSimulateScriptTextForThisInstance(YELL_REDSHARD_TAUNT_3, NPC_LORD_VICTOR_NEFARIUS);
                            break;
                    }
                    m_uiScepterEpicTimer = 2 * HOUR * IN_MILLISECONDS;
                    break;
                case 2:     // 1 hour left
                    switch (urand(0, 1))
                    {
                        case 0:
                            DoOrSimulateScriptTextForThisInstance(YELL_REDSHARD_TAUNT_4, NPC_LORD_VICTOR_NEFARIUS);
                            break;
                        case 1:
                            DoOrSimulateScriptTextForThisInstance(YELL_REDSHARD_TAUNT_5, NPC_LORD_VICTOR_NEFARIUS);
                            break;
                    }
                    m_uiScepterEpicTimer = 30 * MINUTE * IN_MILLISECONDS;
                    break;
                case 3:     // 30 min left
                    DoOrSimulateScriptTextForThisInstance(YELL_REDSHARD_TAUNT_6, NPC_LORD_VICTOR_NEFARIUS);
                    m_uiScepterEpicTimer = 30 * MINUTE * IN_MILLISECONDS;
                    break;
                case 4:     // Failure
                    SetData(TYPE_QUEST_SCEPTER, FAIL);
                    if (GetData(TYPE_NEFARIAN) == NOT_STARTED)
                    {
                        DoOrSimulateScriptTextForThisInstance(EMOTE_REDSHARD_TAUNT_2, NPC_LORD_VICTOR_NEFARIUS);
                        DoOrSimulateScriptTextForThisInstance(YELL_REDSHARD_TAUNT_7, NPC_LORD_VICTOR_NEFARIUS);
                    }
                default:    // Something weird happened: stop timer and fail the event
                    m_uiScepterEpicTimer = 0;
                    SetData(TYPE_QUEST_SCEPTER, FAIL);
                    break;
            }
            m_uiScepterQuestStep++;
        }
        else
            m_uiScepterEpicTimer -= uiDiff;
    }

    // Reset Razorgore in case of wipe
    if (m_uiResetTimer)
    {
        if (m_uiResetTimer <= uiDiff)
        {
            // Respawn Razorgore
            if (Creature* pRazorgore = GetSingleCreatureFromStorage(NPC_RAZORGORE))
            {
                if (!pRazorgore->isAlive())
                    pRazorgore->Respawn();
            }

            // Respawn the Dragon Eggs
            for (GuidList::const_iterator itr = m_lDragonEggsGuids.begin(); itr != m_lDragonEggsGuids.end(); ++itr)
            {
                if (GameObject* pEgg = instance->GetGameObject(*itr))
                {
                    if (!pEgg->isSpawned())
                        pEgg->Respawn();
                }
            }

            m_uiResetTimer = 0;
        }
        else
            m_uiResetTimer -= uiDiff;
    }

    if (GetData(TYPE_RAZORGORE) != IN_PROGRESS)
        return;

    if (m_uiDefenseTimer < uiDiff)
    {
        // Randomize generators
        std::random_shuffle(m_vGeneratorGuids.begin(), m_vGeneratorGuids.end());

        // Spawn the defenders
        for (uint8 i = 0; i < MAX_EGGS_DEFENDERS; ++i)
        {
            Creature* pGenerator = instance->GetCreature(m_vGeneratorGuids[i]);
            if (!pGenerator)
                continue;

            // Defenders are spawned randomly, 4 at a time
            // There can be up to 12 Dragonspawns spawned and 40 Orcs (either mage or legionnaire)
            // If one of the cap is reached, only the remaining type of NPC is spawned until the second cap is also reached

            uint32 uiSpellId = 0;                                                   // Hold the spell summoning the NPC defender for that generator
            uint8 uiMaxRange = (m_uiDragonspawnCount < MAX_DRAGONSPAWN ? 3 : 1);    // If all dragonspawns are already spawned, don't roll for them below

            switch (urand(0, uiMaxRange))
            {
                case 0:
                    if (m_uiBlackwingDefCount < MAX_BLACKWING_DEFENDER)
                        uiSpellId = SPELL_SUMMON_LEGIONNAIRE;
                    break;
                case 1:
                    if (m_uiBlackwingDefCount < MAX_BLACKWING_DEFENDER)
                        uiSpellId = SPELL_SUMMON_MAGE;
                    break;
                case 2:
                case 3:
                    uiSpellId = SPELL_SUMMON_DRAGONSPAWN;
                    break;
            }

            if (uiSpellId != 0)
                pGenerator->CastSpell(pGenerator, uiSpellId, TRIGGERED_NONE);
        }

        m_uiDefenseTimer = 15000;
    }
    else
        m_uiDefenseTimer -= uiDiff;
}
void instance_stratholme::SetData(uint32 uiType, uint32 uiData)
{
    // TODO: Remove the hard-coded indexes from array accessing
    switch (uiType)
    {
        case TYPE_BARON_RUN:
            switch (uiData)
            {
                case IN_PROGRESS:
                    if (m_auiEncounter[uiType] == IN_PROGRESS || m_auiEncounter[uiType] == FAIL)
                        break;

                    // Baron ultimatum starts: summon Ysida in the cage
                    if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                    {
                        DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_START, NPC_BARON);
                        if (Creature* pYsida = pBaron->SummonCreature(NPC_YSIDA, aStratholmeLocation[7].m_fX, aStratholmeLocation[7].m_fY, aStratholmeLocation[7].m_fZ, aStratholmeLocation[7].m_fO, TEMPSPAWN_DEAD_DESPAWN, 0))
                            pYsida->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER | UNIT_NPC_FLAG_GOSSIP);
                    }

                    m_uiBaronRunTimer = 45 * MINUTE * IN_MILLISECONDS;
                    debug_log("SD2: Instance Stratholme: Baron run in progress.");
                    break;
                case FAIL:
                    // may add code to remove aura from players, but in theory the time should be up already and removed.
                    break;
                case DONE:
                    m_uiBaronRunTimer = 0;
                    break;
            }
            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_BARONESS:
        case TYPE_NERUB:
        case TYPE_PALLID:
            m_auiEncounter[uiType] = uiData;
            if (uiData == DONE)
            {
                DoSortZiggurats();
                DoUseDoorOrButton(m_zigguratStorage[uiType - TYPE_BARONESS].m_doorGuid);
            }
            if (uiData == SPECIAL)
                StartSlaugtherSquare();
            break;
        case TYPE_RAMSTEIN:
            if (uiData == SPECIAL)
            {
                if (m_auiEncounter[uiType] != SPECIAL && m_auiEncounter[uiType] != DONE)
                {
                    m_uiSlaugtherSquareTimer = 20000;       // TODO - unknown, also possible that this is not the very correct place..
                    DoUseDoorOrButton(GO_PORT_GAUNTLET);
                }

                uint32 uiCount = m_sAbomnationGUID.size();
                for (GuidSet::iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end();)
                {
                    if (Creature* pAbom = instance->GetCreature(*itr))
                    {
                        ++itr;
                        if (!pAbom->isAlive())
                            --uiCount;
                    }
                    else
                    {
                        // Remove obsolete guid from set and decrement count
                        m_sAbomnationGUID.erase(itr++);
                        --uiCount;
                    }
                }

                if (!uiCount)
                {
                    // Open the Slaughterhouse door and set a timer to close it after 10 sec to let some time to Ramstein to move out
                    DoOpenSlaughterhouseDoor(true);
                    m_uiSlaughterDoorTimer = 10000;

                    // No more handlng of Abomnations
                    m_uiSlaugtherSquareTimer = 0;

                    if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                    {
                        DoScriptText(SAY_ANNOUNCE_RAMSTEIN, pBaron);
                        if (Creature* pRamstein = pBaron->SummonCreature(NPC_RAMSTEIN, aStratholmeLocation[2].m_fX, aStratholmeLocation[2].m_fY, aStratholmeLocation[2].m_fZ, aStratholmeLocation[2].m_fO, TEMPSPAWN_DEAD_DESPAWN, 0))
                            pRamstein->GetMotionMaster()->MovePoint(0, aStratholmeLocation[5].m_fX, aStratholmeLocation[5].m_fY, aStratholmeLocation[5].m_fZ);

                        debug_log("SD2: Instance Stratholme - Slaugther event: Ramstein spawned.");
                    }
                }
                else
                    debug_log("SD2: Instance Stratholme - Slaugther event: %u Abomnation left to kill.", uiCount);
            }
            // After fail aggroing Ramstein means wipe on Ramstein, so close door again
            if (uiData == IN_PROGRESS && m_auiEncounter[uiType] == FAIL)
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
            if (uiData == DONE)
            {
                // Open side gate and start summoning skeletons
                DoUseDoorOrButton(GO_PORT_SLAUGHTER_GATE);
                // Close the Slaughterhouse door in case it was open again after a wipe on Ramstein
                DoOpenSlaughterhouseDoor(false);
                // use this timer as a bool just to start summoning
                m_uiMindlessSummonTimer = 500;
                m_uiMindlessCount = 0;
                m_luiUndeadGUIDs.clear();

                // Summon 5 guards
                if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                {
                    for (uint8 i = 0; i < 5; ++i)
                    {
                        float fX, fY, fZ;
                        pBaron->GetRandomPoint(aStratholmeLocation[6].m_fX, aStratholmeLocation[6].m_fY, aStratholmeLocation[6].m_fZ, 5.0f, fX, fY, fZ);
                        if (Creature* pTemp = pBaron->SummonCreature(NPC_BLACK_GUARD, aStratholmeLocation[6].m_fX, aStratholmeLocation[6].m_fY, aStratholmeLocation[6].m_fZ, aStratholmeLocation[6].m_fO, TEMPSPAWN_DEAD_DESPAWN, 0))
                            m_luiGuardGUIDs.push_back(pTemp->GetObjectGuid());
                    }

                    debug_log("SD2: Instance Stratholme - Slaugther event: Summoned 5 guards.");
                }
            }
            // Open Door again and stop Abomnation
            if (uiData == FAIL && m_auiEncounter[uiType] != FAIL)
            {
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
                m_uiSlaugtherSquareTimer = 0;

                // Let already moving Abomnations stop
                for (auto itr : m_sAbomnationGUID)
                {
                    Creature* pAbom = instance->GetCreature(itr);
                    if (pAbom && pAbom->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
                        pAbom->GetMotionMaster()->MovementExpired();
                }
            }

            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_BARON:
            if (uiData == IN_PROGRESS)
            {
                // Close Slaughterhouse door if needed
                if (m_auiEncounter[uiType] == FAIL)
                    DoUseDoorOrButton(GO_PORT_GAUNTLET);

                // If Aurius was given the medaillon wait 5s before summoning him
                if (GetData(TYPE_AURIUS) == DONE)
                    m_uiAuriusSummonTimer = 5000;
            }
            else if (uiData == DONE)
            {
                // Players successfully engaged Baron within the time-limit of his ultimatum
                //     Note: UpdateAI() prevents TYPE_BARON_RUN to be marked as FAILED if the
                //     Baron is already engaged (in progress) when the ultimatum timer expires
                if (m_auiEncounter[TYPE_BARON_RUN] == IN_PROGRESS)
                {
                    SetData(TYPE_BARON_RUN, DONE);
                    Map::PlayerList const& players = instance->GetPlayers();

                    for (const auto& player : players)
                    {
                        if (Player* pPlayer = player.getSource())
                        {
                            if (pPlayer->HasAura(SPELL_BARON_ULTIMATUM))
                                pPlayer->RemoveAurasDueToSpell(SPELL_BARON_ULTIMATUM);

                            if (pPlayer->GetQuestStatus(QUEST_DEAD_MAN_PLEA) == QUEST_STATUS_INCOMPLETE)
                                pPlayer->KilledMonsterCredit(NPC_YSIDA);

                            // Argent Dawn reputation reward
                            pPlayer->CastSpell(pPlayer, SPELL_YSIDA_FREED, TRIGGERED_OLD_TRIGGERED);
                        }
                    }

                    // Open cage, finish rescue event
                    if (Creature* pYsida = GetSingleCreatureFromStorage(NPC_YSIDA))
                    {
                        DoScriptText(SAY_EPILOGUE, pYsida);
                        DoUseDoorOrButton(GO_YSIDA_CAGE);
                        pYsida->GetMotionMaster()->MovePoint(0, aStratholmeLocation[8].m_fX, aStratholmeLocation[8].m_fY, aStratholmeLocation[8].m_fZ);
                        pYsida->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER | UNIT_NPC_FLAG_GOSSIP);
                    }
                }

                // If Aurius was spawned to help fight the Baron
                if (GetData(TYPE_AURIUS) == DONE)
                {
                    // Baron killed and Aurius is alive: give him his NPC Flags back, so players can complete the quest and fake his death
                    if (Creature* pAurius = GetSingleCreatureFromStorage(NPC_AURIUS))
                    {
                        if (pAurius->isAlive())
                        {
                            DoScriptText(SAY_AURIUS_DEATH, pAurius);
                            pAurius->StopMoving();
                            pAurius->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER | UNIT_NPC_FLAG_GOSSIP);
                            pAurius->InterruptNonMeleeSpells(true);
                            pAurius->SetHealth(1);
                            pAurius->GetMotionMaster()->MovementExpired();
                            pAurius->GetMotionMaster()->MoveIdle();
                            pAurius->RemoveAllAurasOnDeath();
                            pAurius->SetStandState(UNIT_STAND_STATE_DEAD);
                        }
                    }
                }

                // Open Slaughterhouse door again
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
            }
            else if (uiData == FAIL)
                DoUseDoorOrButton(GO_PORT_GAUNTLET);

            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_BARTHILAS_RUN:
            if (uiData == IN_PROGRESS)
            {
                Creature* pBarthilas = GetSingleCreatureFromStorage(NPC_BARTHILAS);
                if (pBarthilas && pBarthilas->isAlive() && !pBarthilas->isInCombat())
                {
                    DoScriptText(SAY_WARN_BARON, pBarthilas);
                    pBarthilas->SetWalk(false);
                    pBarthilas->GetMotionMaster()->MovePoint(0, aStratholmeLocation[0].m_fX, aStratholmeLocation[0].m_fY, aStratholmeLocation[0].m_fZ);

                    m_uiBarthilasRunTimer = 8000;
                }
            }
            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_BLACK_GUARDS:
            // Prevent double action
            if (m_auiEncounter[uiType] == uiData)
                return;

            // Restart after failure, close Gauntlet
            if (uiData == IN_PROGRESS && m_auiEncounter[uiType] == FAIL)
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
            // Wipe case - open gauntlet
            if (uiData == FAIL)
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
            if (uiData == DONE)
            {
                if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                    DoScriptText(SAY_UNDEAD_DEFEAT, pBaron);
                DoOpenSlaughterhouseDoor(true);
                DoUseDoorOrButton(GO_ZIGGURAT_DOOR_5);
            }
            m_auiEncounter[uiType] = uiData;

            // No need to save anything here, so return
            return;
        case TYPE_POSTMASTER:
            m_auiEncounter[uiType] = uiData;
            if (uiData == IN_PROGRESS)
            {
                ++m_uiPostboxesUsed;

                // After the second post box prepare to spawn the Post Master
                if (m_uiPostboxesUsed == 2)
                    SetData(TYPE_POSTMASTER, SPECIAL);
            }
            // No need to save anything here, so return
            return;
        case TYPE_TRUE_MASTERS:
            m_auiEncounter[uiType] = uiData;
            if (uiData == SPECIAL)
            {
                ++m_uiSilverHandKilled;

                // When the 5th paladin is killed set data to DONE in order to give the quest credit for the last paladin
                if (m_uiSilverHandKilled == MAX_SILVERHAND)
                    SetData(TYPE_TRUE_MASTERS, DONE);
            }
            // No need to save anything here, so return
            return;
        case TYPE_AURIUS:
            // Prevent further players to complete the quest in that instance or autocomplete the follow-up quest. the flag will be set back if event is succeed
            if (uiData == DONE)
            {
                if (Creature* pAurius = GetSingleCreatureFromStorage(NPC_AURIUS))
                    pAurius->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER);
            }
            m_auiEncounter[uiType] = uiData;
            break;
    }

    if (uiData == DONE)
    {
        OUT_SAVE_INST_DATA;

        std::ostringstream saveStream;
        saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " "
                   << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " "
                   << m_auiEncounter[6] << " " << m_auiEncounter[7];

        m_strInstData = saveStream.str();

        SaveToDB();
        OUT_SAVE_INST_DATA_COMPLETE;
    }
}
void instance_stratholme::Update(uint32 uiDiff)
{
    if (m_uiBarthilasRunTimer)
    {
        if (m_uiBarthilasRunTimer <= uiDiff)
        {
            Creature* pBarthilas = GetSingleCreatureFromStorage(NPC_BARTHILAS);
            if (pBarthilas && pBarthilas->isAlive() && !pBarthilas->isInCombat())
                pBarthilas->NearTeleportTo(aStratholmeLocation[1].m_fX, aStratholmeLocation[1].m_fY, aStratholmeLocation[1].m_fZ, aStratholmeLocation[1].m_fO);

            SetData(TYPE_BARTHILAS_RUN, DONE);
            m_uiBarthilasRunTimer = 0;
        }
        else
            m_uiBarthilasRunTimer -= uiDiff;
    }

    if (m_uiBaronRunTimer)
    {
        if (m_uiYellCounter == 0 && m_uiBaronRunTimer <= 10*MINUTE*IN_MILLISECONDS)
        {
            DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_10_MIN, NPC_BARON);
            ++m_uiYellCounter;
        }
        else if (m_uiYellCounter == 1 && m_uiBaronRunTimer <= 5*MINUTE*IN_MILLISECONDS)
        {
            DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_5_MIN, NPC_BARON);
            ++m_uiYellCounter;
        }

        if (m_uiBaronRunTimer <= uiDiff)
        {
            SetData(TYPE_BARON_RUN, FAIL);

            DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_FAIL, NPC_BARON);

            m_uiBaronRunTimer = 0;
            debug_log("SD2: Instance Stratholme: Baron run event reached end. Event has state %u.", GetData(TYPE_BARON_RUN));
        }
        else
            m_uiBaronRunTimer -= uiDiff;
    }

    if (m_uiMindlessSummonTimer)
    {
        if (m_uiMindlessCount < 30)
        {
            if (m_uiMindlessSummonTimer <= uiDiff)
            {
                if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                {
                    // Summon mindless skeletons and move them to random point in the center of the square
                    if (Creature* pTemp = pBaron->SummonCreature(NPC_MINDLESS_UNDEAD, aStratholmeLocation[4].m_fX, aStratholmeLocation[4].m_fY, aStratholmeLocation[4].m_fZ, aStratholmeLocation[4].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0))
                    {
                        float fX, fY, fZ;
                        pBaron->GetRandomPoint(aStratholmeLocation[5].m_fX, aStratholmeLocation[5].m_fY, aStratholmeLocation[5].m_fZ, 20.0f, fX, fY, fZ);
                        pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ);
                        m_luiUndeadGUIDs.push_back(pTemp->GetObjectGuid());
                        ++m_uiMindlessCount;
                    }
                }
                m_uiMindlessSummonTimer = 400;
            }
            else
                m_uiMindlessSummonTimer -= uiDiff;
        }
        else
            m_uiMindlessSummonTimer = 0;
    }

    if (m_uiSlaugtherSquareTimer)
    {
        if (m_uiSlaugtherSquareTimer <= uiDiff)
        {
            // Call next Abomnations
            for (GuidSet::const_iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end(); ++itr)
            {
                Creature* pAbom = instance->GetCreature(*itr);
                // Skip killed and already walking Abomnations
                if (!pAbom || !pAbom->isAlive() || pAbom->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
                    continue;

                // Let Move to somewhere in the middle
                if (!pAbom->isInCombat())
                {
                    if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_PORT_SLAUGTHER))
                    {
                        float fX, fY, fZ;
                        pAbom->GetRandomPoint(pDoor->GetPositionX(), pDoor->GetPositionY(), pDoor->GetPositionZ(), 10.0f, fX, fY, fZ);
                        pAbom->GetMotionMaster()->MovePoint(0, fX, fY, fZ);
                    }
                }
                break;
            }

            // TODO - how fast are they called?
            m_uiSlaugtherSquareTimer = urand(15000, 30000);
        }
        else
            m_uiSlaugtherSquareTimer -= uiDiff;
    }
}
void instance_stratholme::Update(uint32 uiDiff)
{
    // Loop over the two Gate traps, each one has up to three timers (trap reset, gate opening delay, critters spawning delay)
    for (uint8 i = 0; i < 2; i++)
    {
        // Check that the trap is not on cooldown, if so check if player/pet is in range
        if (m_uiGateTrapTimers[i][0])
        {
            m_uiGateTrapTimers[i][0] -= uiDiff;
            if (m_uiGateTrapTimers[i][0] <= uiDiff)
            {
                debug_log("SD2: Instance Stratholme - Rat Trap reseted %u.", i);
                m_uiGateTrapTimers[i][0] = 0;
            }
        }
        else
        {
            Map::PlayerList const& players = instance->GetPlayers();
            for (const auto& player : players)
            {
                if (Player* pPlayer = player.getSource())
                {
                    if (!pPlayer->isGameMaster() && pPlayer->IsWithinDist2d(aGateTrap[i].m_fX, aGateTrap[i].m_fY, 5.5f))
                        DoGateTrap(i);

                    Pet* pet = pPlayer->GetPet();
                    if (!pPlayer->isGameMaster() && pet && pet->IsWithinDist2d(aGateTrap[i].m_fX, aGateTrap[i].m_fY, 5.5f))
                        DoGateTrap(i);
                }
            }
        }
        // Timer to reopen the gates
        if (m_uiGateTrapTimers[i][1])
        {
            if (m_uiGateTrapTimers[i][1] <= uiDiff)
            {
                DoUseDoorOrButton(aGates[2 * i]);
                DoUseDoorOrButton(aGates[2 * i + 1]);
                m_uiGateTrapTimers[i][1] = 0;
            }
            else
                m_uiGateTrapTimers[i][1] -= uiDiff;
        }
        // Delay timer to spawn the plagued critters once the gate are closing
        if (m_uiGateTrapTimers[i][2])
        {
            if (m_uiGateTrapTimers[i][2] <= uiDiff)
            {
                if (Player* pPlayer = GetPlayerInMap())
                    DoSpawnPlaguedCritters(i, pPlayer);
                m_uiGateTrapTimers[i][2] = 0;
            }
            else
                m_uiGateTrapTimers[i][2] -= uiDiff;
        }
    }

    // Timer to send the Black Guard Sentries out of the Slaughterhouse before Baron Rivendare
    if (m_uiBlackGuardsTimer)
    {
        if (m_uiBlackGuardsTimer <= uiDiff)
        {
            // Open the Slaughterhouse door and set a timer to close it after 10 sec to let some time to the 5 Black Guards to move out
            DoOpenSlaughterhouseDoor(true);
            m_uiSlaughterDoorTimer = 10000;

            for (GuidList::const_iterator itr = m_luiGuardGUIDs.begin(); itr != m_luiGuardGUIDs.end(); ++itr)
            {
                Creature* pGuard = instance->GetCreature(*itr);
                if (pGuard && pGuard->isAlive() && !pGuard->isInCombat())
                {
                    float fX, fY, fZ;
                    pGuard->GetRandomPoint(aStratholmeLocation[5].m_fX, aStratholmeLocation[5].m_fY, aStratholmeLocation[5].m_fZ, 10.0f, fX, fY, fZ);
                    pGuard->GetMotionMaster()->MovePoint(0, fX, fY, fZ);
                }
            }
            m_uiBlackGuardsTimer = 0;
        }
        else
            m_uiBlackGuardsTimer -= uiDiff;
    }
    // Timer to close the gate of the Slaughterhouse before Baron Rivendare after Ramstein/Black Guards moved out
    if (m_uiSlaughterDoorTimer)
    {
        if (m_uiSlaughterDoorTimer <= uiDiff)
        {
            DoOpenSlaughterhouseDoor(false);
            m_uiSlaughterDoorTimer = 0;
        }
        else
            m_uiSlaughterDoorTimer -= uiDiff;
    }
    // Timer to teleport Barthilas
    if (m_uiBarthilasRunTimer)
    {
        if (m_uiBarthilasRunTimer <= uiDiff)
        {
            Creature* pBarthilas = GetSingleCreatureFromStorage(NPC_BARTHILAS);
            if (pBarthilas && pBarthilas->isAlive() && !pBarthilas->isInCombat())
                pBarthilas->NearTeleportTo(aStratholmeLocation[1].m_fX, aStratholmeLocation[1].m_fY, aStratholmeLocation[1].m_fZ, aStratholmeLocation[1].m_fO);

            SetData(TYPE_BARTHILAS_RUN, DONE);
            m_uiBarthilasRunTimer = 0;
        }
        else
            m_uiBarthilasRunTimer -= uiDiff;
    }

    // Timer to summon Aurius into the Slaughter House once Baron is engaged
    if (m_uiAuriusSummonTimer)
    {
        if (m_uiAuriusSummonTimer <= uiDiff)
        {
            // Teleport Aurius from the Chapel and spawn it in the Slaughter House to engage Baron
            Creature* pAurius = GetSingleCreatureFromStorage(NPC_AURIUS);
            if (pAurius && pAurius->isAlive() && !pAurius->isInCombat())
            {
                if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                {
                    float fX, fY, fZ;
                    pBaron->GetRandomPoint(pBaron->GetPositionX(), pBaron->GetPositionY(), pBaron->GetPositionZ(), 4.0f, fX, fY, fZ);
                    pAurius->NearTeleportTo(fX, fY, fZ, pAurius->GetOrientation());
                    pAurius->SetRespawnCoord(fX, fY, fZ, pAurius->GetOrientation());
                    DoScriptText(SAY_AURIUS_AGGRO, pAurius);
                    pAurius->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER | UNIT_NPC_FLAG_GOSSIP);
                    pAurius->AI()->AttackStart(pBaron);
                }
            }
            m_uiAuriusSummonTimer = 0;
        }
        else
            m_uiAuriusSummonTimer -= uiDiff;
    }

    // Check changes for Baron ultimatum timer only if Baron is not already in combat
    if (m_uiBaronRunTimer && GetData(TYPE_BARON) != IN_PROGRESS)
    {
        if (m_uiYellCounter == 0 && m_uiBaronRunTimer <= 10 * MINUTE * IN_MILLISECONDS)
        {
            DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_10_MIN, NPC_BARON);
            ++m_uiYellCounter;
        }
        else if (m_uiYellCounter == 1 && m_uiBaronRunTimer <= 5 * MINUTE * IN_MILLISECONDS)
        {
            DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_5_MIN, NPC_BARON);
            ++m_uiYellCounter;
        }
        // Used to create a delay of 10s between Baron speech and Ysida's answer
        else if (m_uiYellCounter == 2 && m_uiBaronRunTimer <= (5 * MINUTE - 10) * IN_MILLISECONDS)
        {
            DoOrSimulateScriptTextForThisInstance(SAY_YSIDA_RUN_5_MIN, NPC_YSIDA);
            ++m_uiYellCounter;
        }

        if (m_uiBaronRunTimer <= uiDiff)
        {
            if (GetData(TYPE_BARON_RUN) != FAIL)
            {
                SetData(TYPE_BARON_RUN, FAIL);

                // Open the cage and let Ysida face her doom
                if (Creature* pYsida = GetSingleCreatureFromStorage(NPC_YSIDA))
                {
                    pYsida->GetMotionMaster()->MovePoint(0, aStratholmeLocation[8].m_fX, aStratholmeLocation[8].m_fY, aStratholmeLocation[8].m_fZ);
                    DoUseDoorOrButton(GO_YSIDA_CAGE);
                }

                DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_FAIL, NPC_BARON);

                m_uiBaronRunTimer = 8000;  // We reset the timer so the speech of Ysida is not said at the same time than the Baron's one
            }
            else
            {
                // Baron ultimatum failed: let the Baron kill her
                if (Creature* pYsida = GetSingleCreatureFromStorage(NPC_YSIDA))
                {
                    if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                        pBaron->CastSpell(pYsida, SPELL_BARON_SOUL_DRAIN, TRIGGERED_NONE);
                }

                DoOrSimulateScriptTextForThisInstance(SAY_YSIDA_RUN_FAIL, NPC_YSIDA);

                m_uiBaronRunTimer = 0;  // event done for good, no more speech
                debug_log("SD2: Instance Stratholme: Baron run event reached end. Event has state %u.", GetData(TYPE_BARON_RUN));
            }
        }
        else
            m_uiBaronRunTimer -= uiDiff;
    }

    if (m_uiMindlessSummonTimer)
    {
        if (m_uiMindlessCount < 30)
        {
            if (m_uiMindlessSummonTimer <= uiDiff)
            {
                if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                {
                    // Summon mindless skeletons and move them to random point in the center of the square
                    if (Creature* pTemp = pBaron->SummonCreature(NPC_MINDLESS_UNDEAD, aStratholmeLocation[4].m_fX, aStratholmeLocation[4].m_fY, aStratholmeLocation[4].m_fZ, aStratholmeLocation[4].m_fO, TEMPSPAWN_DEAD_DESPAWN, 0))
                    {
                        float fX, fY, fZ;
                        pBaron->GetRandomPoint(aStratholmeLocation[5].m_fX, aStratholmeLocation[5].m_fY, aStratholmeLocation[5].m_fZ, 20.0f, fX, fY, fZ);
                        pTemp->SetWalk(false);
                        pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ);
                        m_luiUndeadGUIDs.push_back(pTemp->GetObjectGuid());
                        ++m_uiMindlessCount;
                    }
                }
                m_uiMindlessSummonTimer = 400;
            }
            else
                m_uiMindlessSummonTimer -= uiDiff;
        }
        else
            m_uiMindlessSummonTimer = 0;
    }

    if (m_uiSlaugtherSquareTimer)
    {
        if (m_uiSlaugtherSquareTimer <= uiDiff)
        {
            // Call next Abomnations
            for (auto itr : m_sAbomnationGUID)
            {
                Creature* pAbom = instance->GetCreature(itr);
                // Skip killed and already walking Abomnations
                if (!pAbom || !pAbom->isAlive() || pAbom->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
                    continue;

                // Let Move to somewhere in the middle
                if (!pAbom->isInCombat())
                {
                    if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_PORT_SLAUGTHER))
                    {
                        float fX, fY, fZ;
                        pAbom->GetRandomPoint(pDoor->GetPositionX(), pDoor->GetPositionY(), pDoor->GetPositionZ(), 10.0f, fX, fY, fZ);
                        pAbom->GetMotionMaster()->MovePoint(0, fX, fY, fZ);
                    }
                }
                break;
            }

            // TODO - how fast are they called?
            m_uiSlaugtherSquareTimer = urand(30000, 45000);
        }
        else
            m_uiSlaugtherSquareTimer -= uiDiff;
    }
}
void instance_stratholme::SetData(uint32 uiType, uint32 uiData)
{
    // TODO: Remove the hard-coded indexes from array accessing
    switch(uiType)
    {
        case TYPE_BARON_RUN:
            switch(uiData)
            {
                case IN_PROGRESS:
                    if (m_auiEncounter[uiType] == IN_PROGRESS || m_auiEncounter[uiType] == FAIL)
                        break;

                    DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_START, NPC_BARON);

                    m_uiBaronRunTimer = 45*MINUTE*IN_MILLISECONDS;
                    debug_log("SD2: Instance Stratholme: Baron run in progress.");
                    break;
                case FAIL:
                    //may add code to remove aura from players, but in theory the time should be up already and removed.
                    break;
                case DONE:
                    m_uiBaronRunTimer = 0;
                    break;
            }
            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_BARONESS:
        case TYPE_NERUB:
        case TYPE_PALLID:
            m_auiEncounter[uiType] = uiData;
            if (uiData == DONE)
            {
                DoSortZiggurats();
                DoUseDoorOrButton(m_zigguratStorage[uiType - TYPE_BARONESS].m_doorGuid);
            }
            if (uiData == SPECIAL)
                StartSlaugtherSquare();
            break;
        case TYPE_RAMSTEIN:
            if (uiData == SPECIAL)
            {
                if (m_auiEncounter[uiType] != SPECIAL && m_auiEncounter[uiType] != DONE)
                {
                    m_uiSlaugtherSquareTimer = 20000;       // TODO - unknown, also possible that this is not the very correct place..
                    DoUseDoorOrButton(GO_PORT_GAUNTLET);
                }

                uint32 uiCount = m_sAbomnationGUID.size();
                for(GuidSet::iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end();)
                {
                    if (Creature* pAbom = instance->GetCreature(*itr))
                    {
                        ++itr;
                        if (!pAbom->isAlive())
                            --uiCount;
                    }
                    else
                    {
                        // Remove obsolete guid from set and decrement count
                        m_sAbomnationGUID.erase(itr++);
                        --uiCount;
                    }
                }

                if (!uiCount)
                {
                    // Old Comment: a bit itchy, it should close GO_ZIGGURAT_DOOR_4 door after 10 secs, but it doesn't. skipping it for now.
                    // However looks like that this door is no more closed
                    DoUseDoorOrButton(GO_ZIGGURAT_DOOR_4);

                    // No more handlng of Abomnations
                    m_uiSlaugtherSquareTimer = 0;

                    if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                    {
                        DoScriptText(SAY_ANNOUNCE_RAMSTEIN, pBaron);
                        if (Creature* pRamstein = pBaron->SummonCreature(NPC_RAMSTEIN, aStratholmeLocation[2].m_fX, aStratholmeLocation[2].m_fY, aStratholmeLocation[2].m_fZ, aStratholmeLocation[2].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0))
                            pRamstein->GetMotionMaster()->MovePoint(0, aStratholmeLocation[3].m_fX, aStratholmeLocation[3].m_fY, aStratholmeLocation[3].m_fZ);

                        debug_log("SD2: Instance Stratholme - Slaugther event: Ramstein spawned.");
                    }
                }
                else
                    debug_log("SD2: Instance Stratholme - Slaugther event: %u Abomnation left to kill.", uiCount);
            }
            // After fail aggroing Ramstein means wipe on Ramstein, so close door again
            if (uiData == IN_PROGRESS && m_auiEncounter[uiType] == FAIL)
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
            if (uiData == DONE)
            {
                // Open side gate and start summoning skeletons
                DoUseDoorOrButton(GO_PORT_SLAUGHTER_GATE);
                // use this timer as a bool just to start summoning
                m_uiMindlessSummonTimer = 500;
                m_uiMindlessCount = 0;
                m_luiUndeadGUIDs.clear();

                // Summon 5 guards
                if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                {
                    for(uint8 i = 0; i < 5; ++i)
                    {
                        float fX, fY, fZ;
                        pBaron->GetRandomPoint(aStratholmeLocation[6].m_fX, aStratholmeLocation[6].m_fY, aStratholmeLocation[6].m_fZ, 5.0f, fX, fY, fZ);
                        if (Creature* pTemp = pBaron->SummonCreature(NPC_BLACK_GUARD, aStratholmeLocation[6].m_fX, aStratholmeLocation[6].m_fY, aStratholmeLocation[6].m_fZ, aStratholmeLocation[6].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0))
                            m_luiGuardGUIDs.push_back(pTemp->GetObjectGuid());
                    }

                    debug_log("SD2: Instance Stratholme - Slaugther event: Summoned 5 guards.");
                }
            }
            // Open Door again and stop Abomnation
            if (uiData == FAIL && m_auiEncounter[uiType] != FAIL)
            {
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
                m_uiSlaugtherSquareTimer = 0;

                // Let already moving Abomnations stop
                for (GuidSet::const_iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end(); ++itr)
                {
                    Creature* pAbom = instance->GetCreature(*itr);
                    if (pAbom && pAbom->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
                        pAbom->GetMotionMaster()->MovementExpired();
                }
            }

            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_BARON:
            if (uiData == IN_PROGRESS)
            {
                // Reached the Baron within time-limit
                if (m_auiEncounter[TYPE_BARON_RUN] == IN_PROGRESS)
                    SetData(TYPE_BARON_RUN, DONE);

                // Close Slaughterhouse door if needed
                if (m_auiEncounter[5] == FAIL)              // TODO
                    DoUseDoorOrButton(GO_PORT_GAUNTLET);
            }
            if (uiData == DONE)
            {
                if (m_auiEncounter[TYPE_BARON_RUN] == DONE)
                {
                    Map::PlayerList const& players = instance->GetPlayers();

                    for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
                    {
                        if (Player* pPlayer = itr->getSource())
                        {
                            if (pPlayer->HasAura(SPELL_BARON_ULTIMATUM))
                                pPlayer->RemoveAurasDueToSpell(SPELL_BARON_ULTIMATUM);

                            if (pPlayer->GetQuestStatus(QUEST_DEAD_MAN_PLEA) == QUEST_STATUS_INCOMPLETE)
                                pPlayer->AreaExploredOrEventHappens(QUEST_DEAD_MAN_PLEA);
                        }
                    }

                    // Open cage and finish rescue event
                    if (Creature* pYsidaT = GetSingleCreatureFromStorage(NPC_YSIDA_TRIGGER))
                    {
                        if (Creature* pYsida = pYsidaT->SummonCreature(NPC_YSIDA, pYsidaT->GetPositionX(), pYsidaT->GetPositionY(), pYsidaT->GetPositionZ(), pYsidaT->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 1800000))
                        {
                            DoScriptText(SAY_EPILOGUE, pYsida);
                            pYsida->GetMotionMaster()->MovePoint(0, aStratholmeLocation[7].m_fX, aStratholmeLocation[7].m_fY, aStratholmeLocation[7].m_fZ);
                        }
                        DoUseDoorOrButton(GO_YSIDA_CAGE);
                    }
                }

                // Open Slaughterhouse door again
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
            }
            if (uiData == FAIL)
                DoUseDoorOrButton(GO_PORT_GAUNTLET);

            m_auiEncounter[5] = uiData;                     // TODO
            break;
        case TYPE_BARTHILAS_RUN:
            if (uiData == IN_PROGRESS)
            {
                Creature* pBarthilas = GetSingleCreatureFromStorage(NPC_BARTHILAS);
                if (pBarthilas && pBarthilas->isAlive() && !pBarthilas->isInCombat())
                {
                    DoScriptText(SAY_WARN_BARON, pBarthilas);
                    pBarthilas->SetWalk(false);
                    pBarthilas->GetMotionMaster()->MovePoint(0, aStratholmeLocation[0].m_fX, aStratholmeLocation[0].m_fY, aStratholmeLocation[0].m_fZ);

                    m_uiBarthilasRunTimer = 8000;
                }
            }
            m_auiEncounter[6] = uiData;                     // TODO
            break;
        case TYPE_BLACK_GUARDS:
            // Prevent double action
            if (m_auiEncounter[7] == uiData)                // TODO
                return;

            // Restart after failure, close Gauntlet
            if (uiData == IN_PROGRESS && m_auiEncounter[7] == FAIL)
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
            // Wipe case - open gauntlet
            if (uiData == FAIL)
                DoUseDoorOrButton(GO_PORT_GAUNTLET);
            if (uiData == DONE)
            {
                if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON))
                    DoScriptText(SAY_UNDEAD_DEFEAT, pBaron);
                DoUseDoorOrButton(GO_ZIGGURAT_DOOR_5);
            }
            m_auiEncounter[7] = uiData;                     // TODO

            // No need to save anything here, so return
            return;

        case TYPE_SH_AELMAR:
            m_bIsSilverHandDead[0] = (uiData) ? true : false;
            break;
        case TYPE_SH_CATHELA:
            m_bIsSilverHandDead[1] = (uiData) ? true : false;
            break;
        case TYPE_SH_GREGOR:
            m_bIsSilverHandDead[2] = (uiData) ? true : false;
            break;
        case TYPE_SH_NEMAS:
            m_bIsSilverHandDead[3] = (uiData) ? true : false;
            break;
        case TYPE_SH_VICAR:
            m_bIsSilverHandDead[4] = (uiData) ? true : false;
            break;
    }

    if (uiData == DONE)
    {
        OUT_SAVE_INST_DATA;

        std::ostringstream saveStream;
        saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " "
            << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6];

        m_strInstData = saveStream.str();

        SaveToDB();
        OUT_SAVE_INST_DATA_COMPLETE;
    }
}
void instance_sunken_temple::SetData(uint32 uiType, uint32 uiData)
{
    switch (uiType)
    {
        case TYPE_ATALARION:
            if (uiData == SPECIAL)
                DoSpawnAtalarionIfCan();
            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_PROTECTORS:
            if (uiData == DONE)
            {
                --m_uiProtectorsRemaining;
                if (!m_uiProtectorsRemaining)
                {
                    m_auiEncounter[uiType] = uiData;
                    DoUseDoorOrButton(GO_JAMMALAN_BARRIER);
                    // Intro yell
                    DoOrSimulateScriptTextForThisInstance(SAY_JAMMALAN_INTRO, NPC_JAMMALAN);
                }
            }
            break;
        case TYPE_JAMMALAN:
            if (uiData == DONE)
            {
                if (Creature* pEranikus = GetSingleCreatureFromStorage(NPC_SHADE_OF_ERANIKUS))
                    pEranikus->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PLAYER);
            }
            m_auiEncounter[uiType] = uiData;
            break;
        case TYPE_AVATAR:
            if (uiData == SPECIAL)
            {
                ++m_uiFlameCounter;

                Creature* pShade = GetSingleCreatureFromStorage(NPC_SHADE_OF_HAKKAR);
                if (!pShade)
                    return;

                switch (m_uiFlameCounter)
                {
                        // Yells on each flame
                        // TODO It might be possible that these yells should be ordered randomly, however this is the seen state
                    case 1: DoScriptText(SAY_AVATAR_BRAZIER_1, pShade); break;
                    case 2: DoScriptText(SAY_AVATAR_BRAZIER_2, pShade); break;
                    case 3: DoScriptText(SAY_AVATAR_BRAZIER_3, pShade); break;
                        // Summon the avatar of all flames are used
                    case MAX_FLAMES:
                        DoScriptText(SAY_AVATAR_BRAZIER_4, pShade);
                        pShade->CastSpell(pShade, SPELL_SUMMON_AVATAR, TRIGGERED_OLD_TRIGGERED);
                        m_uiAvatarSummonTimer = 0;
                        m_uiSupressorTimer = 0;
                        break;
                }

                // Summon the suppressors only after the flames are doused
                // Summon timer is confusing random; timers were: 13, 39 and 52 secs;
                if (m_uiFlameCounter != MAX_FLAMES)
                    m_uiSupressorTimer = urand(15000, 45000);

                return;
            }

            // Prevent double processing
            if (m_auiEncounter[uiType] == uiData)
                return;

            if (uiData == IN_PROGRESS)
            {
                m_uiSupressorTimer = 0;
                DoUpdateFlamesFlags(false);

                // Summon timer; use a small delay
                m_uiAvatarSummonTimer = 3000;
                m_bIsFirstHakkarWave = true;

                // Summon the shade
                Player* pPlayer = GetPlayerInMap();
                if (!pPlayer)
                    return;

                if (Creature* pShade = pPlayer->SummonCreature(NPC_SHADE_OF_HAKKAR, aSunkenTempleLocation[1].m_fX, aSunkenTempleLocation[1].m_fY, aSunkenTempleLocation[1].m_fZ, aSunkenTempleLocation[1].m_fO, TEMPSPAWN_MANUAL_DESPAWN, 0))
                {
                    m_npcEntryGuidStore[NPC_SHADE_OF_HAKKAR] = pShade->GetObjectGuid();
                    pShade->SetRespawnDelay(DAY);
                }

                // Respawn circles
                for (GuidVector::const_iterator itr = m_vuiCircleGUIDs.begin(); itr != m_vuiCircleGUIDs.end(); ++itr)
                    DoRespawnGameObject(*itr, 30 * MINUTE);
            }
            else if (uiData == FAIL)
            {
                // In case of wipe during the summoning ritual the shade is despawned
                // The trash mobs stay in place, they are not despawned; the avatar is not sure if it's despawned or not but most likely he'll stay in place

                // Despawn the shade and the avatar if needed -- TODO, avatar really?
                if (Creature* pShade = GetSingleCreatureFromStorage(NPC_SHADE_OF_HAKKAR))
                    pShade->ForcedDespawn();

                // Reset flames
                DoUpdateFlamesFlags(true);
            }

            // Use combat doors
            DoUseDoorOrButton(GO_HAKKAR_DOOR_1);
            DoUseDoorOrButton(GO_HAKKAR_DOOR_2);

            m_auiEncounter[uiType] = uiData;

            break;
    }

    if (uiData == DONE)
    {
        OUT_SAVE_INST_DATA;

        std::ostringstream saveStream;

        saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " "
                   << m_auiEncounter[3] << " " << m_auiEncounter[4];

        m_strInstData = saveStream.str();

        SaveToDB();
        OUT_SAVE_INST_DATA_COMPLETE;
    }
}