aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/Server/AuthSession.cpp12
-rw-r--r--src/server/game/Handlers/ArenaTeamHandler.cpp4
-rw-r--r--src/server/game/Quests/QuestDef.cpp8
-rw-r--r--src/server/game/Server/WorldSocket.cpp143
-rw-r--r--src/server/game/Server/WorldSocket.h2
-rw-r--r--src/server/game/World/World.cpp12
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp7
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp126
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp144
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp39
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp133
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp16
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp80
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp3
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp16
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp105
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp274
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h39
-rw-r--r--src/server/scripts/Northrend/zone_sholazar_basin.cpp139
-rw-r--r--src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp237
-rw-r--r--src/server/shared/Networking/Socket.h10
-rw-r--r--src/server/worldserver/worldserver.conf.dist9
23 files changed, 827 insertions, 733 deletions
diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp
index 9931595e860..8276183fb10 100644
--- a/src/server/authserver/Server/AuthSession.cpp
+++ b/src/server/authserver/Server/AuthSession.cpp
@@ -83,8 +83,8 @@ typedef struct AUTH_LOGON_PROOF_S
uint8 cmd;
uint8 error;
uint8 M2[20];
- uint32 unk1;
- uint32 unk2;
+ uint32 AccountFlags;
+ uint32 SurveyId;
uint16 unk3;
} sAuthLogonProof_S;
@@ -540,9 +540,9 @@ bool AuthSession::HandleLogonProof()
memcpy(proof.M2, sha.GetDigest(), 20);
proof.cmd = AUTH_LOGON_PROOF;
proof.error = 0;
- proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
- proof.unk2 = 0x00; // SurveyId
- proof.unk3 = 0x00;
+ proof.AccountFlags = 0x00800000; // 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
+ proof.SurveyId = 0;
+ proof.unk3 = 0;
packet.resize(sizeof(proof));
std::memcpy(packet.contents(), &proof, sizeof(proof));
@@ -831,7 +831,7 @@ bool AuthSession::HandleRealmList()
pkt << AmountOfCharacters;
pkt << realm.timezone; // realm category
if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients
- pkt << uint8(0x2C); // unk, may be realm number/id?
+ pkt << uint8(realm.m_ID);
else
pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients
diff --git a/src/server/game/Handlers/ArenaTeamHandler.cpp b/src/server/game/Handlers/ArenaTeamHandler.cpp
index 3bb3edac500..20d89d9efb5 100644
--- a/src/server/game/Handlers/ArenaTeamHandler.cpp
+++ b/src/server/game/Handlers/ArenaTeamHandler.cpp
@@ -311,6 +311,10 @@ void WorldSession::HandleArenaTeamRemoveOpcode(WorldPacket& recvData)
SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
return;
}
+
+ // Player cannot be removed during fights
+ if (arenaTeam->IsFighting())
+ return;
arenaTeam->DelMember(member->Guid, true);
diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp
index a26b14af4b7..eb9b1ad45b9 100644
--- a/src/server/game/Quests/QuestDef.cpp
+++ b/src/server/game/Quests/QuestDef.cpp
@@ -197,18 +197,22 @@ uint32 Quest::XPValue(Player* player) const
int32 Quest::GetRewOrReqMoney() const
{
+ // RequiredMoney: the amount is the negative copper sum.
if (RewardOrRequiredMoney <= 0)
return RewardOrRequiredMoney;
- return int32(RewardOrRequiredMoney * sWorld->getRate(RATE_DROP_MONEY));
+ // RewardMoney: the positive amount
+ return int32(RewardOrRequiredMoney * sWorld->getRate(RATE_MONEY_QUEST));
}
uint32 Quest::GetRewMoneyMaxLevel() const
{
+ // If Quest has flag to not give money on max level, it's 0
if (HasFlag(QUEST_FLAGS_NO_MONEY_FROM_XP))
return 0;
- return RewardMoneyMaxLevel;
+ // Else, return the rewarded copper sum modified by the rate
+ return uint32(RewardMoneyMaxLevel * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST));
}
bool Quest::IsAutoAccept() const
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index d2602e83944..ca8e2cd5a34 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -16,13 +16,14 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <memory>
#include "WorldSocket.h"
#include "BigNumber.h"
#include "Opcodes.h"
+#include "Player.h"
#include "ScriptMgr.h"
#include "SHA1.h"
#include "PacketLog.h"
+#include <memory>
using boost::asio::ip::tcp;
@@ -63,6 +64,22 @@ void WorldSocket::ReadHeaderHandler()
EndianConvertReverse(header->size);
EndianConvert(header->cmd);
+ if (!header->IsValid())
+ {
+ if (_worldSession)
+ {
+ Player* player = _worldSession->GetPlayer();
+ TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %hu, cmd: %u)",
+ _worldSession->GetAccountId(), player ? player->GetGUIDLow() : 0, player ? player->GetName().c_str() : "<none>", header->size, header->cmd);
+ }
+ else
+ TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %hu, cmd: %u)",
+ GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd);
+
+ CloseSocket();
+ return;
+ }
+
AsyncReadData(header->size - sizeof(header->cmd));
}
@@ -70,8 +87,6 @@ void WorldSocket::ReadDataHandler()
{
ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer());
- header->size -= sizeof(header->cmd);
-
uint16 opcode = uint16(header->cmd);
std::string opcodeName = GetOpcodeNameForLogging(opcode);
@@ -106,7 +121,8 @@ void WorldSocket::ReadDataHandler()
if (!_worldSession)
{
TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
- break;
+ CloseSocket();
+ return;
}
// Our Idle timer will reset on any non PING opcodes.
@@ -155,35 +171,30 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
std::string account;
SHA1Hash sha;
uint32 clientBuild;
- uint32 unk2, unk3, unk5, unk6, unk7;
+ uint32 serverId, loginServerType, region, battlegroup, realmIndex;
uint64 unk4;
WorldPacket packet, SendAddonPacked;
BigNumber k;
bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
- if (sWorld->IsClosed())
- {
- SendAuthResponseError(AUTH_REJECT);
- TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str());
- return;
- }
-
// Read the content of the packet
recvPacket >> clientBuild;
- recvPacket >> unk2;
+ recvPacket >> serverId; // Used for GRUNT only
recvPacket >> account;
- recvPacket >> unk3;
+ recvPacket >> loginServerType; // 0 GRUNT, 1 Battle.net
recvPacket >> clientSeed;
- recvPacket >> unk5 >> unk6 >> unk7;
+ recvPacket >> region >> battlegroup; // Used for Battle.net only
+ recvPacket >> realmIndex; // realmId from auth_database.realmlist table
recvPacket >> unk4;
recvPacket.read(digest, 20);
- TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u",
+ TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: client %u, serverId %u, account %s, loginServerType %u, clientseed %u, realmIndex %u",
clientBuild,
- unk2,
+ serverId,
account.c_str(),
- unk3,
- clientSeed);
+ loginServerType,
+ clientSeed,
+ realmIndex);
// Get the account information from the auth database
// 0 1 2 3 4 5 6 7 8
@@ -200,6 +211,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
// We can not log here, as we do not know the account. Thus, no accountId.
SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
+ DelayedCloseSocket();
return;
}
@@ -225,6 +237,57 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
// id has to be fetched at this point, so that first actual account response that fails can be logged
id = fields[0].GetUInt32();
+ k.SetHexStr(fields[1].GetCString());
+
+ // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
+ _authCrypt.Init(&k);
+
+ // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
+ if (sWorld->IsClosed())
+ {
+ SendAuthResponseError(AUTH_REJECT);
+ TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str());
+ DelayedCloseSocket();
+ return;
+ }
+
+ if (realmIndex != realmID)
+ {
+ SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND);
+ TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm).");
+ DelayedCloseSocket();
+ return;
+ }
+
+ std::string os = fields[8].GetString();
+
+ // Must be done before WorldSession is created
+ if (wardenActive && os != "Win" && os != "OSX")
+ {
+ SendAuthResponseError(AUTH_REJECT);
+ TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str());
+ DelayedCloseSocket();
+ return;
+ }
+
+ // Check that Key and account name are the same on client and server
+ uint32 t = 0;
+
+ sha.UpdateData(account);
+ sha.UpdateData((uint8*)&t, 4);
+ sha.UpdateData((uint8*)&clientSeed, 4);
+ sha.UpdateData((uint8*)&_authSeed, 4);
+ sha.UpdateBigNumbers(&k, NULL);
+ sha.Finalize();
+
+ if (memcmp(sha.GetDigest(), digest, 20))
+ {
+ SendAuthResponseError(AUTH_FAILED);
+ TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str());
+ DelayedCloseSocket();
+ return;
+ }
+
///- Re-check ip locking (same check as in auth).
if (fields[3].GetUInt8() == 1) // if ip is locked
{
@@ -234,12 +297,11 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str());
// We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
sScriptMgr->OnFailedAccountLogin(id);
+ DelayedCloseSocket();
return;
}
}
- k.SetHexStr(fields[1].GetCString());
-
int64 mutetime = fields[5].GetInt64();
//! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now.
if (mutetime < 0)
@@ -259,16 +321,6 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
locale = LOCALE_enUS;
uint32 recruiter = fields[7].GetUInt32();
- std::string os = fields[8].GetString();
-
- // Must be done before WorldSession is created
- if (wardenActive && os != "Win" && os != "OSX")
- {
- SendAuthResponseError(AUTH_REJECT);
- TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str());
- return;
- }
-
// Checks gmlevel per Realm
stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID);
@@ -298,6 +350,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
SendAuthResponseError(AUTH_BANNED);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
sScriptMgr->OnFailedAccountLogin(id);
+ DelayedCloseSocket();
return;
}
@@ -309,23 +362,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
SendAuthResponseError(AUTH_UNAVAILABLE);
TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
sScriptMgr->OnFailedAccountLogin(id);
- return;
- }
-
- // Check that Key and account name are the same on client and server
- uint32 t = 0;
-
- sha.UpdateData(account);
- sha.UpdateData((uint8*)&t, 4);
- sha.UpdateData((uint8*)&clientSeed, 4);
- sha.UpdateData((uint8*)&_authSeed, 4);
- sha.UpdateBigNumbers(&k, NULL);
- sha.Finalize();
-
- if (memcmp(sha.GetDigest(), digest, 20))
- {
- SendAuthResponseError(AUTH_FAILED);
- TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str());
+ DelayedCloseSocket();
return;
}
@@ -352,19 +389,15 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
LoginDatabase.Execute(stmt);
- // NOTE ATM the socket is single-threaded, have this in mind ...
- _worldSession = new WorldSession(id, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter);
-
- _authCrypt.Init(&k);
+ // At this point, we can safely hook a successful login
+ sScriptMgr->OnAccountLogin(id);
+ _worldSession = new WorldSession(id, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter);
_worldSession->LoadGlobalAccountData();
_worldSession->LoadTutorialsData();
_worldSession->ReadAddonsInfo(recvPacket);
_worldSession->LoadPermissions();
- // At this point, we can safely hook a successful login
- sScriptMgr->OnAccountLogin(id);
-
// Initialize Warden system only if it is enabled by config
if (wardenActive)
_worldSession->InitWarden(&k, os);
diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h
index faa57b58f93..0667c1b090a 100644
--- a/src/server/game/Server/WorldSocket.h
+++ b/src/server/game/Server/WorldSocket.h
@@ -48,6 +48,8 @@ struct ClientPktHeader
{
uint16 size;
uint32 cmd;
+
+ bool IsValid() const { return size >= 4 && size < 10240 && cmd < NUM_MSG_TYPES; }
};
#pragma pack(pop)
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 3f94cfbf56f..4de9cb34df6 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -557,6 +557,18 @@ void World::LoadConfigSettings(bool reload)
TC_LOG_ERROR("server.loading", "DurabilityLossChance.Block (%f) must be >=0. Using 0.0 instead.", rate_values[RATE_DURABILITY_LOSS_BLOCK]);
rate_values[RATE_DURABILITY_LOSS_BLOCK] = 0.0f;
}
+ rate_values[RATE_MONEY_QUEST] = sConfigMgr->GetFloatDefault("Rate.Quest.Money.Reward", 1.0f);
+ if (rate_values[RATE_MONEY_QUEST] < 0.0f)
+ {
+ TC_LOG_ERROR("server.loading", "Rate.Quest.Money.Reward (%f) must be >=0. Using 0 instead.", rate_values[RATE_MONEY_QUEST]);
+ rate_values[RATE_MONEY_QUEST] = 0.0f;
+ }
+ rate_values[RATE_MONEY_MAX_LEVEL_QUEST] = sConfigMgr->GetFloatDefault("Rate.Quest.Money.Max.Level.Reward", 1.0f);
+ if (rate_values[RATE_MONEY_MAX_LEVEL_QUEST] < 0.0f)
+ {
+ TC_LOG_ERROR("server.loading", "Rate.Quest.Money.Max.Level.Reward (%f) must be >=0. Using 0 instead.", rate_values[RATE_MONEY_MAX_LEVEL_QUEST]);
+ rate_values[RATE_MONEY_MAX_LEVEL_QUEST] = 0.0f;
+ }
///- Read other configuration items from the config file
m_bool_configs[CONFIG_DURABILITY_LOSS_IN_PVP] = sConfigMgr->GetBoolDefault("DurabilityLoss.InPvP", false);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 0711ead6187..cb87e1739c2 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -399,6 +399,8 @@ enum Rates
RATE_DURABILITY_LOSS_ABSORB,
RATE_DURABILITY_LOSS_BLOCK,
RATE_MOVESPEED,
+ RATE_MONEY_QUEST,
+ RATE_MONEY_MAX_LEVEL_QUEST,
MAX_RATES
};
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp
index f18c0aac8bb..26937a83e63 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp
@@ -70,6 +70,11 @@ class boss_arcanist_doan : public CreatureScript
events.ScheduleEvent(EVENT_POLYMORPH, 30 * IN_MILLISECONDS);
}
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ }
+
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
@@ -119,7 +124,7 @@ class boss_arcanist_doan : public CreatureScript
CreatureAI* GetAI(Creature* creature) const override
{
- return new boss_arcanist_doanAI(creature);
+ return GetInstanceAI<boss_arcanist_doanAI>(creature);
}
};
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp
index dd173c75232..72874bba510 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -25,79 +24,104 @@ EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "scarlet_monastery.h"
enum Spells
{
- SPELL_CALLOFTHEGRAVE = 17831,
+ SPELL_CALL_OF_THE_GRAVE = 17831,
SPELL_TERRIFY = 7399,
- SPELL_SOULSIPHON = 7290
+ SPELL_SOUL_SIPHON = 7290
};
-class boss_azshir_the_sleepless : public CreatureScript
+enum Events
{
-public:
- boss_azshir_the_sleepless() : CreatureScript("boss_azshir_the_sleepless") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new boss_azshir_the_sleeplessAI(creature);
- }
-
- struct boss_azshir_the_sleeplessAI : public ScriptedAI
- {
- boss_azshir_the_sleeplessAI(Creature* creature) : ScriptedAI(creature) { }
+ EVENT_CALL_OF_GRAVE = 1,
+ EVENT_TERRIFY,
+ EVENT_SOUL_SIPHON
+};
- uint32 SoulSiphon_Timer;
- uint32 CallOftheGrave_Timer;
- uint32 Terrify_Timer;
+class boss_azshir_the_sleepless : public CreatureScript
+{
+ public:
+ boss_azshir_the_sleepless() : CreatureScript("boss_azshir_the_sleepless") { }
- void Reset() override
+ struct boss_azshir_the_sleeplessAI : public BossAI
{
- SoulSiphon_Timer = 1;
- CallOftheGrave_Timer = 30000;
- Terrify_Timer = 20000;
- }
-
- void EnterCombat(Unit* /*who*/) override { }
+ boss_azshir_the_sleeplessAI(Creature* creature) : BossAI(creature, DATA_AZSHIR)
+ {
+ _siphon = false;
+ }
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ void Reset() override
+ {
+ _Reset();
+ _siphon = false;
+ }
- //If we are <50% hp cast Soul Siphon rank 1
- if (!HealthAbovePct(50) && !me->IsNonMeleeSpellCast(false))
+ void EnterCombat(Unit* /*who*/) override
{
- //SoulSiphon_Timer
- if (SoulSiphon_Timer <= diff)
- {
- DoCastVictim(SPELL_SOULSIPHON);
- return;
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_CALL_OF_GRAVE, 30000);
+ events.ScheduleEvent(EVENT_TERRIFY, 20000);
+ }
- //SoulSiphon_Timer = 20000;
- }
- else SoulSiphon_Timer -= diff;
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
}
- //CallOfTheGrave_Timer
- if (CallOftheGrave_Timer <= diff)
+ void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override
{
- DoCastVictim(SPELL_CALLOFTHEGRAVE);
- CallOftheGrave_Timer = 30000;
+ if (HealthBelowPct(50) && !_siphon)
+ {
+ DoCastVictim(SPELL_SOUL_SIPHON);
+ events.ScheduleEvent(EVENT_SOUL_SIPHON, 20000);
+ _siphon = true;
+ }
}
- else CallOftheGrave_Timer -= diff;
- //Terrify_Timer
- if (Terrify_Timer <= diff)
+ void UpdateAI(uint32 diff) override
{
- DoCastVictim(SPELL_TERRIFY);
- Terrify_Timer = 20000;
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_CALL_OF_GRAVE:
+ DoCastVictim(SPELL_CALL_OF_THE_GRAVE);
+ events.ScheduleEvent(EVENT_CALL_OF_GRAVE, 30000);
+ break;
+ case EVENT_TERRIFY:
+ DoCastVictim(SPELL_TERRIFY);
+ events.ScheduleEvent(EVENT_TERRIFY, 20000);
+ break;
+ case EVENT_SOUL_SIPHON:
+ DoCastVictim(SPELL_SOUL_SIPHON);
+ events.ScheduleEvent(EVENT_SOUL_SIPHON, 20000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
}
- else Terrify_Timer -= diff;
- DoMeleeAttackIfReady();
+ private:
+ bool _siphon;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_azshir_the_sleeplessAI>(creature);
}
- };
};
void AddSC_boss_azshir_the_sleepless()
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp
index 207c12f608a..43a9ef32be6 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -16,15 +15,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Boss_Bloodmage_Thalnos
-SD%Complete: 100
-SDComment:
-SDCategory: Scarlet Monastery
-EndScriptData */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "scarlet_monastery.h"
enum Yells
{
@@ -38,95 +31,102 @@ enum Spells
SPELL_FLAMESHOCK = 8053,
SPELL_SHADOWBOLT = 1106,
SPELL_FLAMESPIKE = 8814,
- SPELL_FIRENOVA = 16079,
+ SPELL_FIRENOVA = 16079
};
-class boss_bloodmage_thalnos : public CreatureScript
+enum Events
{
-public:
- boss_bloodmage_thalnos() : CreatureScript("boss_bloodmage_thalnos") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new boss_bloodmage_thalnosAI(creature);
- }
-
- struct boss_bloodmage_thalnosAI : public ScriptedAI
- {
- boss_bloodmage_thalnosAI(Creature* creature) : ScriptedAI(creature) { }
-
- bool HpYell;
- uint32 FlameShock_Timer;
- uint32 ShadowBolt_Timer;
- uint32 FlameSpike_Timer;
- uint32 FireNova_Timer;
+ EVENT_FLAME_SHOCK = 1,
+ EVENT_SHADOW_BOLT,
+ EVENT_FLAME_SPIKE,
+ EVENT_FIRE_NOVA
+};
- void Reset() override
- {
- HpYell = false;
- FlameShock_Timer = 10000;
- ShadowBolt_Timer = 2000;
- FlameSpike_Timer = 8000;
- FireNova_Timer = 40000;
- }
+class boss_bloodmage_thalnos : public CreatureScript
+{
+ public:
+ boss_bloodmage_thalnos() : CreatureScript("boss_bloodmage_thalnos") { }
- void EnterCombat(Unit* /*who*/) override
+ struct boss_bloodmage_thalnosAI : public BossAI
{
- Talk(SAY_AGGRO);
- }
+ boss_bloodmage_thalnosAI(Creature* creature) : BossAI(creature, DATA_BLOODMAGE_THALNOS)
+ {
+ _hpYell = false;
+ }
- void KilledUnit(Unit* /*Victim*/) override
- {
- Talk(SAY_KILL);
- }
+ void Reset() override
+ {
+ _hpYell = false;
+ _Reset();
+ }
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ void EnterCombat(Unit* /*who*/) override
+ {
+ Talk(SAY_AGGRO);
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_FLAME_SHOCK, 10000);
+ events.ScheduleEvent(EVENT_SHADOW_BOLT, 2000);
+ events.ScheduleEvent(EVENT_FLAME_SPIKE, 8000);
+ events.ScheduleEvent(EVENT_FIRE_NOVA, 40000);
+ }
- //If we are <35% hp
- if (!HpYell && !HealthAbovePct(35))
+ void JustDied(Unit* /*killer*/) override
{
- Talk(SAY_HEALTH);
- HpYell = true;
+ _JustDied();
}
- //FlameShock_Timer
- if (FlameShock_Timer <= diff)
+ void KilledUnit(Unit* /*victim*/) override
{
- DoCastVictim(SPELL_FLAMESHOCK);
- FlameShock_Timer = urand(10000, 15000);
+ Talk(SAY_KILL);
}
- else FlameShock_Timer -= diff;
- //FlameSpike_Timer
- if (FlameSpike_Timer <= diff)
+ void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override
{
- DoCastVictim(SPELL_FLAMESPIKE);
- FlameSpike_Timer = 30000;
+ if (HealthBelowPct(35) && !_hpYell)
+ {
+ Talk(SAY_HEALTH);
+ _hpYell = true;
+ }
}
- else FlameSpike_Timer -= diff;
- //FireNova_Timer
- if (FireNova_Timer <= diff)
+ void ExecuteEvent(uint32 eventId) override
{
- DoCastVictim(SPELL_FIRENOVA);
- FireNova_Timer = 40000;
+ switch (eventId)
+ {
+ case EVENT_FLAME_SHOCK:
+ DoCastVictim(SPELL_FLAMESHOCK);
+ events.ScheduleEvent(EVENT_FLAME_SHOCK, urand(10000, 15000));
+ break;
+ case EVENT_SHADOW_BOLT:
+ DoCastVictim(SPELL_SHADOWBOLT);
+ events.ScheduleEvent(EVENT_SHADOW_BOLT, 2000);
+ break;
+ case EVENT_FLAME_SPIKE:
+ DoCastVictim(SPELL_FLAMESPIKE);
+ events.ScheduleEvent(EVENT_FLAME_SPIKE, 30000);
+ break;
+ case EVENT_FIRE_NOVA:
+ DoCastVictim(SPELL_FIRENOVA);
+ events.ScheduleEvent(EVENT_FIRE_NOVA, 40000);
+ break;
+ default:
+ break;
+ }
}
- else FireNova_Timer -= diff;
- //ShadowBolt_Timer
- if (ShadowBolt_Timer <= diff)
+ void UpdateAI(uint32 diff) override
{
- DoCastVictim(SPELL_SHADOWBOLT);
- ShadowBolt_Timer = 2000;
+ BossAI::UpdateAI(diff);
}
- else ShadowBolt_Timer -= diff;
- DoMeleeAttackIfReady();
+ private:
+ bool _hpYell;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_bloodmage_thalnosAI>(creature);
}
- };
};
void AddSC_boss_bloodmage_thalnos()
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
index 5939d4a41db..cad46b84748 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
@@ -155,13 +155,13 @@ public:
{
npc_wisp_invisAI(Creature* creature) : ScriptedAI(creature)
{
- Creaturetype = delay = spell = spell2 = 0;
+ Creaturetype = delay = _spell = _spell2 = 0;
}
uint32 Creaturetype;
uint32 delay;
- uint32 spell;
- uint32 spell2;
+ uint32 _spell;
+ uint32 _spell2;
void Reset() override { }
void EnterCombat(Unit* /*who*/) override { }
void SetType(uint32 _type)
@@ -169,24 +169,24 @@ public:
switch (Creaturetype = _type)
{
case 1:
- spell = SPELL_PUMPKIN_AURA_GREEN;
+ _spell = SPELL_PUMPKIN_AURA_GREEN;
break;
case 2:
delay = 15000;
- spell = SPELL_BODY_FLAME;
- spell2 = SPELL_DEATH;
+ _spell = SPELL_BODY_FLAME;
+ _spell2 = SPELL_DEATH;
break;
case 3:
delay = 15000;
- spell = SPELL_SMOKE;
+ _spell = SPELL_SMOKE;
break;
case 4:
delay = 7000;
- spell2 = SPELL_WISP_BLUE;
+ _spell2 = SPELL_WISP_BLUE;
break;
}
- if (spell)
- DoCast(me, spell);
+ if (_spell)
+ DoCast(me, _spell);
}
void SpellHit(Unit* /*caster*/, const SpellInfo* spell) override
@@ -196,7 +196,6 @@ public:
}
void MoveInLineOfSight(Unit* who) override
-
{
if (!who || Creaturetype != 1 || !who->isTargetableForAttack())
return;
@@ -212,8 +211,8 @@ public:
if (delay <= diff)
{
me->RemoveAurasDueToSpell(SPELL_SMOKE);
- if (spell2)
- DoCast(me, spell2);
+ if (_spell2)
+ DoCast(me, _spell2);
delay = 0;
} else delay -= diff;
}
@@ -435,7 +434,7 @@ public:
}
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
- //instance->SetData(DATA_HORSEMAN_EVENT, NOT_STARTED);
+ //instance->SetBossState(DATA_HORSEMAN_EVENT, NOT_STARTED);
}
void FlyMode()
@@ -471,7 +470,7 @@ public:
break;
}
case 6:
- instance->SetData(GAMEOBJECT_PUMPKIN_SHRINE, 0); //hide gameobject
+ instance->SetData(DATA_PUMPKIN_SHRINE, 0); //hide gameobject
break;
case 19:
me->SetDisableGravity(false);
@@ -493,7 +492,7 @@ public:
void EnterCombat(Unit* /*who*/) override
{
- instance->SetData(DATA_HORSEMAN_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_HORSEMAN_EVENT, IN_PROGRESS);
DoZoneInCombat();
}
@@ -503,7 +502,6 @@ public:
}
void MoveInLineOfSight(Unit* who) override
-
{
if (withhead && Phase != 0)
ScriptedAI::MoveInLineOfSight(who);
@@ -567,7 +565,7 @@ public:
flame->CastSpell(flame, SPELL_BODY_FLAME, false);
if (Creature* wisp = DoSpawnCreature(WISP_INVIS, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 60000))
ENSURE_AI(npc_wisp_invis::npc_wisp_invisAI, wisp->AI())->SetType(4);
- instance->SetData(DATA_HORSEMAN_EVENT, DONE);
+ instance->SetBossState(DATA_HORSEMAN_EVENT, DONE);
Map::PlayerList const& players = me->GetMap()->GetPlayers();
if (!players.isEmpty())
@@ -852,7 +850,6 @@ public:
}
void MoveInLineOfSight(Unit* who) override
-
{
if (!who || !me->IsValidAttackTarget(who) || me->GetVictim())
return;
@@ -880,9 +877,9 @@ public:
InstanceScript* instance = player->GetInstanceScript();
if (instance)
{
- if (instance->GetData(DATA_HORSEMAN_EVENT) != NOT_STARTED)
+ if (instance->GetBossState(DATA_HORSEMAN_EVENT) != NOT_STARTED)
return true;
- instance->SetData(DATA_HORSEMAN_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_HORSEMAN_EVENT, IN_PROGRESS);
}
/* if (soil->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER && player->getLevel() > 64)
{
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp
index 480b354fe29..0b7ad73fefd 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp
@@ -26,6 +26,7 @@ EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedEscortAI.h"
+#include "scarlet_monastery.h"
enum Says
{
@@ -44,89 +45,103 @@ enum Spells
SPELL_FRENZY = 8269
};
-enum Entry
+enum Npcs
{
- ENTRY_SCARLET_TRAINEE = 6575,
- ENTRY_SCARLET_MYRMIDON = 4295
+ NPC_SCARLET_TRAINEE = 6575,
+ NPC_SCARLET_MYRMIDON = 4295
};
-class boss_herod : public CreatureScript
+enum Events
{
-public:
- boss_herod() : CreatureScript("boss_herod") { }
+ EVENT_CLEAVE = 1,
+ EVENT_WHIRLWIND
+};
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new boss_herodAI(creature);
- }
+Position const ScarletTraineePos = { 1939.18f, -431.58f, 17.09f, 6.22f };
- struct boss_herodAI : public ScriptedAI
- {
- boss_herodAI(Creature* creature) : ScriptedAI(creature) { }
+class boss_herod : public CreatureScript
+{
+ public:
+ boss_herod() : CreatureScript("boss_herod") { }
- bool Enrage;
+ struct boss_herodAI : public BossAI
+ {
+ boss_herodAI(Creature* creature) : BossAI(creature, DATA_HEROD)
+ {
+ _enrage = false;
+ }
- uint32 Cleave_Timer;
- uint32 Whirlwind_Timer;
+ void Reset() override
+ {
+ _enrage = false;
+ _Reset();
+ }
- void Reset() override
- {
- Enrage = false;
- Cleave_Timer = 12000;
- Whirlwind_Timer = 60000;
- }
+ void EnterCombat(Unit* /*who*/) override
+ {
+ Talk(SAY_AGGRO);
+ DoCast(me, SPELL_RUSHINGCHARGE);
+ _EnterCombat();
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
- DoCast(me, SPELL_RUSHINGCHARGE);
- }
+ events.ScheduleEvent(EVENT_CLEAVE, 12000);
+ events.ScheduleEvent(EVENT_WHIRLWIND, 60000);
+ }
- void KilledUnit(Unit* /*victim*/) override
- {
- Talk(SAY_KILL);
- }
+ void KilledUnit(Unit* /*victim*/) override
+ {
+ Talk(SAY_KILL);
+ }
- void JustDied(Unit* /*killer*/) override
- {
- for (uint8 i = 0; i < 20; ++i)
- me->SummonCreature(ENTRY_SCARLET_TRAINEE, 1939.18f, -431.58f, 17.09f, 6.22f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000);
- }
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ for (uint8 i = 0; i < 20; ++i)
+ me->SummonCreature(NPC_SCARLET_TRAINEE, ScarletTraineePos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000);
+ }
- //If we are <30% hp goes Enraged
- if (!Enrage && !HealthAbovePct(30) && !me->IsNonMeleeSpellCast(false))
+ void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override
{
- Talk(EMOTE_ENRAGE);
- Talk(SAY_ENRAGE);
- DoCast(me, SPELL_FRENZY);
- Enrage = true;
+ if (HealthBelowPct(30) && !_enrage)
+ {
+ Talk(EMOTE_ENRAGE);
+ Talk(SAY_ENRAGE);
+ DoCast(me, SPELL_FRENZY);
+ _enrage = true;
+ }
}
- //Cleave_Timer
- if (Cleave_Timer <= diff)
+ void ExecuteEvent(uint32 eventId) override
{
- DoCastVictim(SPELL_CLEAVE);
- Cleave_Timer = 12000;
+ switch (eventId)
+ {
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ events.ScheduleEvent(EVENT_CLEAVE, 12000);
+ break;
+ case EVENT_WHIRLWIND:
+ Talk(SAY_WHIRLWIND);
+ DoCastVictim(SPELL_WHIRLWIND);
+ events.ScheduleEvent(EVENT_WHIRLWIND, 30000);
+ break;
+ default:
+ break;
+ }
}
- else Cleave_Timer -= diff;
- // Whirlwind_Timer
- if (Whirlwind_Timer <= diff)
+ void UpdateAI(uint32 diff) override
{
- Talk(SAY_WHIRLWIND);
- DoCastVictim(SPELL_WHIRLWIND);
- Whirlwind_Timer = 30000;
+ BossAI::UpdateAI(diff);
}
- else Whirlwind_Timer -= diff;
+
+ private:
+ bool _enrage;
+ };
- DoMeleeAttackIfReady();
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_herodAI>(creature);
}
- };
};
class npc_scarlet_trainee : public CreatureScript
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp
index f58ab1519e4..a4a3660b360 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp
@@ -25,6 +25,7 @@ EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "scarlet_monastery.h"
enum Spells
{
@@ -43,12 +44,15 @@ public:
CreatureAI* GetAI(Creature* creature) const override
{
- return new boss_high_inquisitor_fairbanksAI(creature);
+ return GetInstanceAI<boss_high_inquisitor_fairbanksAI>(creature);
}
struct boss_high_inquisitor_fairbanksAI : public ScriptedAI
{
- boss_high_inquisitor_fairbanksAI(Creature* creature) : ScriptedAI(creature) { }
+ boss_high_inquisitor_fairbanksAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = creature->GetInstanceScript();
+ }
uint32 CurseOfBlood_Timer;
uint32 DispelMagic_Timer;
@@ -57,6 +61,7 @@ public:
uint32 Sleep_Timer;
uint32 Dispel_Timer;
bool PowerWordShield;
+ InstanceScript* instance;
void Reset() override
{
@@ -69,12 +74,19 @@ public:
PowerWordShield = false;
me->SetStandState(UNIT_STAND_STATE_DEAD);
me->SetUInt32Value(UNIT_FIELD_BYTES_1, 7);
+ instance->SetBossState(DATA_HIGH_INQUISITOR_FAIRBANKS, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
+ instance->SetBossState(DATA_HIGH_INQUISITOR_FAIRBANKS, IN_PROGRESS);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ instance->SetBossState(DATA_HIGH_INQUISITOR_FAIRBANKS, DONE);
}
void UpdateAI(uint32 diff) override
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp
index 5aa9729a7e8..40c7667843b 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -16,15 +15,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Boss_Houndmaster_Loksey
-SD%Complete: 100
-SDComment:
-SDCategory: Scarlet Monastery
-EndScriptData */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "scarlet_monastery.h"
enum Yells
{
@@ -37,47 +30,60 @@ enum Spells
SPELL_BLOODLUST = 6742
};
-class boss_houndmaster_loksey : public CreatureScript
+enum Events
{
-public:
- boss_houndmaster_loksey() : CreatureScript("boss_houndmaster_loksey") { }
+ EVENT_BLOODLUST = 1
+};
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new boss_houndmaster_lokseyAI(creature);
- }
+class boss_houndmaster_loksey : public CreatureScript
+{
+ public:
+ boss_houndmaster_loksey() : CreatureScript("boss_houndmaster_loksey") { }
- struct boss_houndmaster_lokseyAI : public ScriptedAI
- {
- boss_houndmaster_lokseyAI(Creature* creature) : ScriptedAI(creature) { }
+ struct boss_houndmaster_lokseyAI : public BossAI
+ {
+ boss_houndmaster_lokseyAI(Creature* creature) : BossAI(creature, DATA_HOUNDMASTER_LOKSEY) { }
- uint32 BloodLust_Timer;
+ void Reset() override
+ {
+ _Reset();
+ }
- void Reset() override
- {
- BloodLust_Timer = 20000;
- }
+ void EnterCombat(Unit* /*who*/) override
+ {
+ Talk(SAY_AGGRO);
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_BLOODLUST, 20000);
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
- }
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ }
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_BLOODLUST:
+ DoCast(me, SPELL_BLOODLUST);
+ events.ScheduleEvent(EVENT_BLOODLUST, 20000);
+ break;
+ default:
+ break;
+ }
+ }
- if (BloodLust_Timer <= diff)
+ void UpdateAI(uint32 diff) override
{
- DoCast(me, SPELL_BLOODLUST);
- BloodLust_Timer = 20000;
+ BossAI::UpdateAI(diff);
}
- else BloodLust_Timer -= diff;
+ };
- DoMeleeAttackIfReady();
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_houndmaster_lokseyAI>(creature);
}
- };
};
void AddSC_boss_houndmaster_loksey()
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp
index a7c795a81f6..a73cf946a7c 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp
@@ -69,11 +69,13 @@ public:
ShadowWordPain_Timer = 5000;
Yell60 = false;
Yell30 = false;
+ instance->SetBossState(DATA_INTERROGATOR_VISHAS, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
+ instance->SetBossState(DATA_INTERROGATOR_VISHAS, IN_PROGRESS);
}
void KilledUnit(Unit* /*Victim*/) override
@@ -86,6 +88,7 @@ public:
//Any other Actions to do with vorrel? setStandState?
if (Creature* vorrel = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_VORREL)))
vorrel->AI()->Talk(SAY_TRIGGER_VORREL);
+ instance->SetBossState(DATA_INTERROGATOR_VISHAS, DONE);
}
void UpdateAI(uint32 diff) override
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp
index 25bb08620a1..a9988584edd 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp
@@ -95,7 +95,7 @@ public:
me->SetStandState(UNIT_STAND_STATE_STAND);
if (me->IsAlive())
- instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED);
_bHasDied = false;
_bHeal = false;
@@ -104,8 +104,8 @@ public:
void JustReachedHome() override
{
- if (instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) != NOT_STARTED)
- instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, FAIL);
+ if (instance->GetBossState(DATA_MOGRAINE_AND_WHITE_EVENT) != NOT_STARTED)
+ instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, FAIL);
}
void EnterCombat(Unit* /*who*/) override
@@ -129,7 +129,7 @@ public:
//On first death, fake death and open door, as well as initiate whitemane if exist
if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_WHITEMANE)))
{
- instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS);
Whitemane->GetMotionMaster()->MovePoint(1, 1163.113370f, 1398.856812f, 32.527786f);
@@ -163,7 +163,7 @@ public:
Talk(SAY_MO_RESURRECTED);
_bFakeDeath = false;
- instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, SPECIAL);
+ instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, SPECIAL);
}
}
@@ -172,7 +172,7 @@ public:
if (!UpdateVictim())
return;
- if (_bHasDied && !_bHeal && instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == SPECIAL)
+ if (_bHasDied && !_bHeal && instance->GetBossState(DATA_MOGRAINE_AND_WHITE_EVENT) == SPECIAL)
{
//On resurrection, stop fake death and heal whitemane and resume fight
if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_WHITEMANE)))
@@ -254,12 +254,12 @@ public:
_bCanResurrect = false;
if (me->IsAlive())
- instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED);
}
void AttackStart(Unit* who) override
{
- if (instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == NOT_STARTED)
+ if (instance->GetBossState(DATA_MOGRAINE_AND_WHITE_EVENT) == NOT_STARTED)
return;
ScriptedAI::AttackStart(who);
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp
index 3ed32b71cbb..24efd7017ec 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp
@@ -25,84 +25,87 @@ EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "scarlet_monastery.h"
enum Spells
{
SPELL_LICHSLAP = 28873,
- SPELL_FROSTBOLTVOLLEY = 8398,
+ SPELL_FROSTBOLT_VOLLEY = 8398,
SPELL_MINDFLAY = 17313,
SPELL_FROSTNOVA = 15531
};
-class boss_scorn : public CreatureScript
+enum Events
{
-public:
- boss_scorn() : CreatureScript("boss_scorn") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new boss_scornAI(creature);
- }
-
- struct boss_scornAI : public ScriptedAI
- {
- boss_scornAI(Creature* creature) : ScriptedAI(creature) { }
+ EVENT_LICH_SLAP = 1,
+ EVENT_FROSTBOLT_VOLLEY,
+ EVENT_MIND_FLAY,
+ EVENT_FROST_NOVA
+};
- uint32 LichSlap_Timer;
- uint32 FrostboltVolley_Timer;
- uint32 MindFlay_Timer;
- uint32 FrostNova_Timer;
+class boss_scorn : public CreatureScript
+{
+ public:
+ boss_scorn() : CreatureScript("boss_scorn") { }
- void Reset() override
+ struct boss_scornAI : public BossAI
{
- LichSlap_Timer = 45000;
- FrostboltVolley_Timer = 30000;
- MindFlay_Timer = 30000;
- FrostNova_Timer = 30000;
- }
-
- void EnterCombat(Unit* /*who*/) override { }
+ boss_scornAI(Creature* creature) : BossAI(creature, DATA_SCORN) { }
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ void Reset() override
+ {
+ _Reset();
+ }
- //LichSlap_Timer
- if (LichSlap_Timer <= diff)
+ void EnterCombat(Unit* /*who*/) override
{
- DoCastVictim(SPELL_LICHSLAP);
- LichSlap_Timer = 45000;
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_LICH_SLAP, 45000);
+ events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 30000);
+ events.ScheduleEvent(EVENT_MIND_FLAY, 30000);
+ events.ScheduleEvent(EVENT_FROST_NOVA, 30000);
}
- else LichSlap_Timer -= diff;
- //FrostboltVolley_Timer
- if (FrostboltVolley_Timer <= diff)
+ void JustDied(Unit* /*killer*/) override
{
- DoCastVictim(SPELL_FROSTBOLTVOLLEY);
- FrostboltVolley_Timer = 20000;
+ _JustDied();
}
- else FrostboltVolley_Timer -= diff;
- //MindFlay_Timer
- if (MindFlay_Timer <= diff)
+ void ExecuteEvent(uint32 eventId) override
{
- DoCastVictim(SPELL_MINDFLAY);
- MindFlay_Timer = 20000;
+ switch (eventId)
+ {
+ case EVENT_LICH_SLAP:
+ DoCastVictim(SPELL_LICHSLAP);
+ events.ScheduleEvent(EVENT_LICH_SLAP, 45000);
+ break;
+ case EVENT_FROSTBOLT_VOLLEY:
+ DoCastVictim(SPELL_FROSTBOLT_VOLLEY);
+ events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 20000);
+ break;
+ case EVENT_MIND_FLAY:
+ DoCastVictim(SPELL_MINDFLAY);
+ events.ScheduleEvent(EVENT_MIND_FLAY, 20000);
+ break;
+ case EVENT_FROST_NOVA:
+ DoCastVictim(SPELL_FROSTNOVA);
+ events.ScheduleEvent(EVENT_FROST_NOVA, 15000);
+ break;
+ default:
+ break;
+ }
}
- else MindFlay_Timer -= diff;
- //FrostNova_Timer
- if (FrostNova_Timer <= diff)
+ void UpdateAI(uint32 diff) override
{
- DoCastVictim(SPELL_FROSTNOVA);
- FrostNova_Timer = 15000;
+ BossAI::UpdateAI(diff);
}
- else FrostNova_Timer -= diff;
+ };
- DoMeleeAttackIfReady();
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_scornAI>(creature);
}
- };
};
void AddSC_boss_scorn()
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp
index dc564e43af5..78837912688 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -16,146 +15,205 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Instance_Scarlet_Monastery
-SD%Complete: 50
-SDComment:
-SDCategory: Scarlet Monastery
-EndScriptData */
-
#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
+#include "InstanceScript.h"
#include "scarlet_monastery.h"
-enum Entry
+DoorData const doorData[] =
{
- ENTRY_PUMPKIN_SHRINE = 186267,
- ENTRY_HORSEMAN = 23682,
- ENTRY_HEAD = 23775,
- ENTRY_PUMPKIN = 23694
+ { GO_HIGH_INQUISITORS_DOOR, DATA_MOGRAINE_AND_WHITE_EVENT, DOOR_TYPE_ROOM, BOUNDARY_NONE },
+ { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END
};
-#define MAX_ENCOUNTER 2
-
class instance_scarlet_monastery : public InstanceMapScript
{
-public:
- instance_scarlet_monastery() : InstanceMapScript("instance_scarlet_monastery", 189) { }
+ public:
+ instance_scarlet_monastery() : InstanceMapScript("instance_scarlet_monastery", 189) { }
- InstanceScript* GetInstanceScript(InstanceMap* map) const override
- {
- return new instance_scarlet_monastery_InstanceMapScript(map);
- }
+ struct instance_scarlet_monastery_InstanceMapScript : public InstanceScript
+ {
+ instance_scarlet_monastery_InstanceMapScript(Map* map) : InstanceScript(map)
+ {
+ SetBossNumber(EncounterCount);
+ LoadDoorData(doorData);
- struct instance_scarlet_monastery_InstanceMapScript : public InstanceScript
- {
- instance_scarlet_monastery_InstanceMapScript(Map* map) : InstanceScript(map) { }
+ PumpkinShrineGUID = 0;
+ HorsemanGUID = 0;
+ HeadGUID = 0;
+ MograineGUID = 0;
+ WhitemaneGUID = 0;
+ VorrelGUID = 0;
- uint64 PumpkinShrineGUID;
- uint64 HorsemanGUID;
- uint64 HeadGUID;
- std::set<uint64> HorsemanAdds;
+ HorsemanAdds.clear();
+ }
- uint64 MograineGUID;
- uint64 WhitemaneGUID;
- uint64 VorrelGUID;
- uint64 DoorHighInquisitorGUID;
+ void OnGameObjectCreate(GameObject* go) override
+ {
+ switch (go->GetEntry())
+ {
+ case GO_PUMPKIN_SHRINE:
+ PumpkinShrineGUID = go->GetGUID();
+ break;
+ case GO_HIGH_INQUISITORS_DOOR:
+ AddDoor(go, true);
+ break;
+ default:
+ break;
+ }
+ }
- uint32 encounter[MAX_ENCOUNTER];
+ void OnGameObjectRemove(GameObject* go) override
+ {
+ switch (go->GetEntry())
+ {
+ case GO_HIGH_INQUISITORS_DOOR:
+ AddDoor(go, false);
+ break;
+ default:
+ break;
+ }
+ }
- void Initialize() override
- {
- memset(&encounter, 0, sizeof(encounter));
+ void OnCreatureCreate(Creature* creature) override
+ {
+ switch (creature->GetEntry())
+ {
+ case NPC_HORSEMAN:
+ HorsemanGUID = creature->GetGUID();
+ break;
+ case NPC_HEAD:
+ HeadGUID = creature->GetGUID();
+ break;
+ case NPC_PUMPKIN:
+ HorsemanAdds.insert(creature->GetGUID());
+ break;
+ case NPC_MOGRAINE:
+ MograineGUID = creature->GetGUID();
+ break;
+ case NPC_WHITEMANE:
+ WhitemaneGUID = creature->GetGUID();
+ break;
+ case NPC_VORREL:
+ VorrelGUID = creature->GetGUID();
+ break;
+ default:
+ break;
+ }
+ }
- PumpkinShrineGUID = 0;
- HorsemanGUID = 0;
- HeadGUID = 0;
- HorsemanAdds.clear();
+ void SetData(uint32 type, uint32 /*data*/) override
+ {
+ switch (type)
+ {
+ case DATA_PUMPKIN_SHRINE:
+ HandleGameObject(PumpkinShrineGUID, false);
+ break;
+ default:
+ break;
+ }
+ }
- MograineGUID = 0;
- WhitemaneGUID = 0;
- VorrelGUID = 0;
- DoorHighInquisitorGUID = 0;
- }
+ bool SetBossState(uint32 type, EncounterState state) override
+ {
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
- void OnGameObjectCreate(GameObject* go) override
- {
- switch (go->GetEntry())
+ switch (type)
+ {
+ case DATA_HORSEMAN_EVENT:
+ if (state == DONE)
+ {
+ for (uint64 guid : HorsemanAdds)
+ {
+ Creature* add = instance->GetCreature(guid);
+ if (add && add->IsAlive())
+ add->Kill(add);
+ }
+ HorsemanAdds.clear();
+ HandleGameObject(PumpkinShrineGUID, false);
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ uint64 GetData64(uint32 type) const override
{
- case ENTRY_PUMPKIN_SHRINE: PumpkinShrineGUID = go->GetGUID();break;
- case 104600: DoorHighInquisitorGUID = go->GetGUID(); break;
+ switch (type)
+ {
+ case DATA_MOGRAINE:
+ return MograineGUID;
+ case DATA_WHITEMANE:
+ return WhitemaneGUID;
+ case DATA_VORREL:
+ return VorrelGUID;
+ default:
+ break;
+ }
+ return 0;
}
- }
- void OnCreatureCreate(Creature* creature) override
- {
- switch (creature->GetEntry())
+ std::string GetSaveData() override
{
- case ENTRY_HORSEMAN: HorsemanGUID = creature->GetGUID(); break;
- case ENTRY_HEAD: HeadGUID = creature->GetGUID(); break;
- case ENTRY_PUMPKIN: HorsemanAdds.insert(creature->GetGUID());break;
- case 3976: MograineGUID = creature->GetGUID(); break;
- case 3977: WhitemaneGUID = creature->GetGUID(); break;
- case 3981: VorrelGUID = creature->GetGUID(); break;
+ OUT_SAVE_INST_DATA;
+
+ std::ostringstream saveStream;
+ saveStream << "S M " << GetBossSaveData();
+
+ OUT_SAVE_INST_DATA_COMPLETE;
+ return saveStream.str();
}
- }
- void SetData(uint32 type, uint32 data) override
- {
- switch (type)
+ void Load(const char* str) override
{
- case TYPE_MOGRAINE_AND_WHITE_EVENT:
- if (data == IN_PROGRESS)
- DoUseDoorOrButton(DoorHighInquisitorGUID);
- if (data == FAIL)
- DoUseDoorOrButton(DoorHighInquisitorGUID);
-
- encounter[0] = data;
- break;
- case GAMEOBJECT_PUMPKIN_SHRINE:
- HandleGameObject(PumpkinShrineGUID, false);
- break;
- case DATA_HORSEMAN_EVENT:
- encounter[1] = data;
- if (data == DONE)
+ if (!str)
{
- for (std::set<uint64>::const_iterator itr = HorsemanAdds.begin(); itr != HorsemanAdds.end(); ++itr)
+ OUT_LOAD_INST_DATA_FAIL;
+ return;
+ }
+
+ OUT_LOAD_INST_DATA(str);
+
+ char dataHead1, dataHead2;
+
+ std::istringstream loadStream(str);
+ loadStream >> dataHead1 >> dataHead2;
+
+ if (dataHead1 == 'S' && dataHead2 == 'M')
+ {
+ for (uint8 i = 0; i < EncounterCount; ++i)
{
- Creature* add = instance->GetCreature(*itr);
- if (add && add->IsAlive())
- add->Kill(add);
+ uint32 tmpState;
+ loadStream >> tmpState;
+ if (tmpState == IN_PROGRESS || tmpState > SPECIAL)
+ tmpState = NOT_STARTED;
+
+ SetBossState(i, EncounterState(tmpState));
}
- HorsemanAdds.clear();
- HandleGameObject(PumpkinShrineGUID, false);
}
- break;
- }
- }
+ else
+ OUT_LOAD_INST_DATA_FAIL;
- uint64 GetData64(uint32 type) const override
- {
- switch (type)
- {
- //case GAMEOBJECT_PUMPKIN_SHRINE: return PumpkinShrineGUID;
- //case DATA_HORSEMAN: return HorsemanGUID;
- //case DATA_HEAD: return HeadGUID;
- case DATA_MOGRAINE: return MograineGUID;
- case DATA_WHITEMANE: return WhitemaneGUID;
- case DATA_VORREL: return VorrelGUID;
- case DATA_DOOR_WHITEMANE: return DoorHighInquisitorGUID;
+ OUT_LOAD_INST_DATA_COMPLETE;
}
- return 0;
- }
- uint32 GetData(uint32 type) const override
+ protected:
+ uint64 PumpkinShrineGUID;
+ uint64 HorsemanGUID;
+ uint64 HeadGUID;
+ uint64 MograineGUID;
+ uint64 WhitemaneGUID;
+ uint64 VorrelGUID;
+
+ std::set<uint64> HorsemanAdds;
+ };
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
- if (type == TYPE_MOGRAINE_AND_WHITE_EVENT)
- return encounter[0];
- if (type == DATA_HORSEMAN_EVENT)
- return encounter[1];
- return 0;
+ return new instance_scarlet_monastery_InstanceMapScript(map);
}
- };
};
void AddSC_instance_scarlet_monastery()
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h
index bdac6b089fd..40089cd9817 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -19,19 +18,43 @@
#ifndef SCARLET_M_
#define SCARLET_M_
+uint32 const EncounterCount = 10;
+
enum DataTypes
{
- TYPE_MOGRAINE_AND_WHITE_EVENT = 1,
-
+ DATA_MOGRAINE_AND_WHITE_EVENT = 1,
DATA_MOGRAINE = 2,
DATA_WHITEMANE = 3,
- DATA_DOOR_WHITEMANE = 4,
- DATA_HORSEMAN_EVENT = 5,
- GAMEOBJECT_PUMPKIN_SHRINE = 6,
+ DATA_HORSEMAN_EVENT = 4,
+ DATA_PUMPKIN_SHRINE = 5,
+
+ DATA_VORREL = 6,
+ DATA_ARCANIST_DOAN = 7,
+ DATA_AZSHIR = 8,
+ DATA_BLOODMAGE_THALNOS = 9,
+ DATA_HEROD = 10,
+ DATA_HIGH_INQUISITOR_FAIRBANKS = 11,
+ DATA_HOUNDMASTER_LOKSEY = 12,
+ DATA_INTERROGATOR_VISHAS = 13,
+ DATA_SCORN = 14
+};
+
+enum CreatureIds
+{
+ NPC_MOGRAINE = 3976,
+ NPC_WHITEMANE = 3977,
+ NPC_VORREL = 3981,
+
+ NPC_HORSEMAN = 23682,
+ NPC_HEAD = 23775,
+ NPC_PUMPKIN = 23694
+};
- DATA_VORREL = 7,
- DATA_ARCANIST_DOAN = 8
+enum GameObjectIds
+{
+ GO_HIGH_INQUISITORS_DOOR = 104600,
+ GO_PUMPKIN_SHRINE = 186267
};
#endif // SCARLET_M_
diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
index f9fb3801955..c56739c783f 100644
--- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp
+++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
@@ -18,12 +18,11 @@
/* ScriptData
SDName: Sholazar_Basin
SD%Complete: 100
-SDComment: Quest support: 12570, 12573, 12621, 12726
+SDComment: Quest support: 12573, 12621, 12726
SDCategory: Sholazar_Basin
EndScriptData */
/* ContentData
-npc_injured_rainspeaker_oracle
npc_vekjik
avatar_of_freya
npc_haiphoon (Quest: "Song of Wind and Water")
@@ -40,141 +39,6 @@ EndContentData */
#include "Player.h"
/*######
-## npc_injured_rainspeaker_oracle
-######*/
-
-#define GOSSIP_ITEM1 "I am ready to travel to your village now."
-
-enum Rainspeaker
-{
- SAY_START_IRO = 0,
- SAY_QUEST_ACCEPT_IRO = 1,
- SAY_END_IRO = 2,
-
- QUEST_FORTUNATE_MISUNDERSTANDINGS = 12570,
- FACTION_ESCORTEE_A = 774,
- FACTION_ESCORTEE_H = 775
-};
-
-class npc_injured_rainspeaker_oracle : public CreatureScript
-{
-public:
- npc_injured_rainspeaker_oracle() : CreatureScript("npc_injured_rainspeaker_oracle") { }
-
- struct npc_injured_rainspeaker_oracleAI : public npc_escortAI
- {
- npc_injured_rainspeaker_oracleAI(Creature* creature) : npc_escortAI(creature) { c_guid = creature->GetGUID(); }
-
- uint64 c_guid;
-
- void Reset() override
- {
- me->RestoreFaction();
- // if we will have other way to assign this to only one npc remove this part
- if (GUID_LOPART(me->GetGUID()) != 101030)
- {
- me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER);
- me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- }
- }
-
- void WaypointReached(uint32 waypointId) override
- {
- Player* player = GetPlayerForEscort();
- if (!player)
- return;
-
- switch (waypointId)
- {
- case 1:
- SetRun();
- break;
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 16:
- case 17:
- case 18:
- me->RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
- me->SetSpeed(MOVE_SWIM, 0.85f, true);
- me->SetSwim(true);
- me->SetDisableGravity(true);
- break;
- case 19:
- me->GetMotionMaster()->MoveFall();
- break;
- case 28:
- player->GroupEventHappens(QUEST_FORTUNATE_MISUNDERSTANDINGS, me);
- // me->RestoreFaction();
- Talk(SAY_END_IRO);
- SetRun(false);
- break;
- }
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (!HasEscortState(STATE_ESCORT_ESCORTING))
- return;
-
- if (Player* player = GetPlayerForEscort())
- {
- if (player->GetQuestStatus(QUEST_FORTUNATE_MISUNDERSTANDINGS) != QUEST_STATUS_COMPLETE)
- player->FailQuest(QUEST_FORTUNATE_MISUNDERSTANDINGS);
- }
- }
- };
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- if (player->GetQuestStatus(QUEST_FORTUNATE_MISUNDERSTANDINGS) == QUEST_STATUS_INCOMPLETE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
-
- player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
-
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- if (action == GOSSIP_ACTION_INFO_DEF+1)
- {
- ENSURE_AI(npc_escortAI, (creature->AI()))->Start(true, false, player->GetGUID());
- ENSURE_AI(npc_escortAI, (creature->AI()))->SetMaxPlayerDistance(35.0f);
- creature->AI()->Talk(SAY_START_IRO);
-
- switch (player->GetTeam()){
- case ALLIANCE:
- creature->setFaction(FACTION_ESCORTEE_A);
- break;
- case HORDE:
- creature->setFaction(FACTION_ESCORTEE_H);
- break;
- }
- }
- return true;
- }
-
- bool OnQuestAccept(Player* /*player*/, Creature* creature, Quest const* /*_Quest*/) override
- {
- creature->AI()->Talk(SAY_QUEST_ACCEPT_IRO);
- return false;
- }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_injured_rainspeaker_oracleAI(creature);
- }
-};
-
-/*######
## npc_vekjik
######*/
@@ -1143,7 +1007,6 @@ public:
void AddSC_sholazar_basin()
{
- new npc_injured_rainspeaker_oracle();
new npc_vekjik();
new npc_avatar_of_freya();
new npc_bushwhacker();
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp
index dc0a6643624..d4fdb262c8e 100644
--- a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp
+++ b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp
@@ -19,156 +19,169 @@
#include "ScriptedCreature.h"
#include "steam_vault.h"
-enum HydromancerThespia
+enum Yells
{
SAY_SUMMON = 0,
SAY_AGGRO = 1,
SAY_SLAY = 2,
SAY_DEAD = 3,
+};
+enum Spells
+{
SPELL_LIGHTNING_CLOUD = 25033,
SPELL_LUNG_BURST = 31481,
- SPELL_ENVELOPING_WINDS = 31718,
+ SPELL_ENVELOPING_WINDS = 31718
+};
- SPELL_WATER_BOLT_VOLLEY = 34449,
- H_SPELL_WATER_BOLT_VOLLEY = 37924
+enum Events
+{
+ EVENT_LIGHTNING_CLOUD = 1,
+ EVENT_LUNG_BURST,
+ EVENT_ENVELOPING_WINDS
};
class boss_hydromancer_thespia : public CreatureScript
{
-public:
- boss_hydromancer_thespia() : CreatureScript("boss_hydromancer_thespia") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_thespiaAI>(creature);
- }
-
- struct boss_thespiaAI : public ScriptedAI
- {
- boss_thespiaAI(Creature* creature) : ScriptedAI(creature)
- {
- instance = creature->GetInstanceScript();
- }
-
- InstanceScript* instance;
-
- uint32 LightningCloud_Timer;
- uint32 LungBurst_Timer;
- uint32 EnvelopingWinds_Timer;
-
- void Reset() override
- {
- LightningCloud_Timer = 15000;
- LungBurst_Timer = 7000;
- EnvelopingWinds_Timer = 9000;
-
- instance->SetBossState(DATA_HYDROMANCER_THESPIA, NOT_STARTED);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_DEAD);
-
- instance->SetBossState(DATA_HYDROMANCER_THESPIA, DONE);
- }
-
- void KilledUnit(Unit* /*victim*/) override
- {
- Talk(SAY_SLAY);
- }
+ public:
+ boss_hydromancer_thespia() : CreatureScript("boss_hydromancer_thespia") { }
- void EnterCombat(Unit* /*who*/) override
+ struct boss_thespiaAI : public BossAI
{
- Talk(SAY_AGGRO);
+ boss_thespiaAI(Creature* creature) : BossAI(creature, DATA_HYDROMANCER_THESPIA) { }
- instance->SetBossState(DATA_HYDROMANCER_THESPIA, IN_PROGRESS);
- }
+ void Reset() override
+ {
+ _Reset();
+ }
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ void JustDied(Unit* /*killer*/) override
+ {
+ Talk(SAY_DEAD);
+ _JustDied();
+ }
- //LightningCloud_Timer
- if (LightningCloud_Timer <= diff)
+ void KilledUnit(Unit* who) override
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
- DoCast(target, SPELL_LIGHTNING_CLOUD);
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
- //cast twice in Heroic mode
- if (IsHeroic())
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
- DoCast(target, SPELL_LIGHTNING_CLOUD);
+ void EnterCombat(Unit* /*who*/) override
+ {
+ Talk(SAY_AGGRO);
+ _EnterCombat();
- LightningCloud_Timer = 15000 + rand32() % 10000;
- } else LightningCloud_Timer -=diff;
+ events.ScheduleEvent(EVENT_LIGHTNING_CLOUD, 15000);
+ events.ScheduleEvent(EVENT_LUNG_BURST, 7000);
+ events.ScheduleEvent(EVENT_ENVELOPING_WINDS, 9000);
+ }
- //LungBurst_Timer
- if (LungBurst_Timer <= diff)
+ void ExecuteEvent(uint32 eventId) override
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
- DoCast(target, SPELL_LUNG_BURST);
- LungBurst_Timer = 7000 + rand32() % 5000;
- } else LungBurst_Timer -=diff;
-
- //EnvelopingWinds_Timer
- if (EnvelopingWinds_Timer <= diff)
+ switch (eventId)
+ {
+ case EVENT_LIGHTNING_CLOUD:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true))
+ DoCast(target, SPELL_LIGHTNING_CLOUD);
+ // cast twice in Heroic mode
+ if (IsHeroic())
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true))
+ DoCast(target, SPELL_LIGHTNING_CLOUD);
+
+ events.ScheduleEvent(EVENT_LIGHTNING_CLOUD, urand(15000, 25000));
+ break;
+ case EVENT_LUNG_BURST:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true))
+ DoCast(target, SPELL_LUNG_BURST);
+ events.ScheduleEvent(EVENT_LUNG_BURST, urand(7000, 12000));
+ break;
+ case EVENT_ENVELOPING_WINDS:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 35.0f, true))
+ DoCast(target, SPELL_ENVELOPING_WINDS);
+ // cast twice in Heroic mode
+ if (IsHeroic())
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 35.0f, true))
+ DoCast(target, SPELL_ENVELOPING_WINDS);
+
+ events.ScheduleEvent(EVENT_ENVELOPING_WINDS, urand(10000, 15000));
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
- DoCast(target, SPELL_ENVELOPING_WINDS);
-
- //cast twice in Heroic mode
- if (IsHeroic())
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
- DoCast(target, SPELL_ENVELOPING_WINDS);
- EnvelopingWinds_Timer = 10000 + rand32() % 5000;
- } else EnvelopingWinds_Timer -=diff;
+ BossAI::UpdateAI(diff);
+ }
+ };
- DoMeleeAttackIfReady();
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_thespiaAI>(creature);
}
- };
+};
+enum CoilfangWaterElemental
+{
+ EVENT_WATER_BOLT_VOLLEY = 1,
+ SPELL_WATER_BOLT_VOLLEY = 34449
};
class npc_coilfang_waterelemental : public CreatureScript
{
-public:
- npc_coilfang_waterelemental() : CreatureScript("npc_coilfang_waterelemental") { }
+ public:
+ npc_coilfang_waterelemental() : CreatureScript("npc_coilfang_waterelemental") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_coilfang_waterelementalAI(creature);
- }
-
- struct npc_coilfang_waterelementalAI : public ScriptedAI
- {
- npc_coilfang_waterelementalAI(Creature* creature) : ScriptedAI(creature) { }
-
- uint32 WaterBoltVolley_Timer;
-
- void Reset() override
+ struct npc_coilfang_waterelementalAI : public ScriptedAI
{
- WaterBoltVolley_Timer = 3000 + rand32() % 3000;
- }
-
- void EnterCombat(Unit* /*who*/) override { }
+ npc_coilfang_waterelementalAI(Creature* creature) : ScriptedAI(creature) { }
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ void Reset() override
+ {
+ _events.Reset();
+ }
- if (WaterBoltVolley_Timer <= diff)
+ void EnterCombat(Unit* /*who*/) override
{
- DoCast(me, SPELL_WATER_BOLT_VOLLEY);
- WaterBoltVolley_Timer = 7000 + rand32() % 5000;
- } else WaterBoltVolley_Timer -= diff;
+ _events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(3000, 6000));
+ }
- DoMeleeAttackIfReady();
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_WATER_BOLT_VOLLEY:
+ DoCast(me, SPELL_WATER_BOLT_VOLLEY);
+ _events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(7000, 12000));
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ EventMap _events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_coilfang_waterelementalAI(creature);
}
- };
-
};
void AddSC_boss_hydromancer_thespia()
diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h
index a13a079ff6c..3bd30bd731b 100644
--- a/src/server/shared/Networking/Socket.h
+++ b/src/server/shared/Networking/Socket.h
@@ -42,7 +42,7 @@ class Socket : public std::enable_shared_from_this<T>
public:
Socket(tcp::socket&& socket, std::size_t headerSize) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
- _remotePort(_socket.remote_endpoint().port()), _readHeaderBuffer(), _readDataBuffer(), _closed(false)
+ _remotePort(_socket.remote_endpoint().port()), _readHeaderBuffer(), _readDataBuffer(), _closed(false), _closing(false)
{
_readHeaderBuffer.Grow(headerSize);
}
@@ -126,7 +126,7 @@ public:
std::placeholders::_1, std::placeholders::_2));
}
- bool IsOpen() const { return !_closed; }
+ bool IsOpen() const { return !_closed && !_closing; }
virtual void CloseSocket()
{
@@ -140,6 +140,9 @@ public:
shutdownError.value(), shutdownError.message().c_str());
}
+ /// Marks the socket for closing after write buffer becomes empty
+ void DelayedCloseSocket() { _closing = true; }
+
virtual bool IsHeaderReady() const { return _readHeaderBuffer.IsMessageReady(); }
virtual bool IsDataReady() const { return _readDataBuffer.IsMessageReady(); }
@@ -221,6 +224,8 @@ private:
if (!_writeQueue.empty())
AsyncWrite(_writeQueue.front());
+ else if (_closing)
+ CloseSocket();
}
else
CloseSocket();
@@ -241,6 +246,7 @@ private:
MessageBuffer _readDataBuffer;
std::atomic<bool> _closed;
+ std::atomic<bool> _closing;
};
#endif // __SOCKET_H__
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index dd8f213b6df..d98a061b9f3 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1741,6 +1741,15 @@ Rate.XP.Quest = 1
Rate.XP.Explore = 1
#
+# Rate.Quest.Money.Reward
+# Rate.Quest.Money.Max.Level.Reward
+# Description: Multiplier for money quest rewards. Can not be below 0.
+# Default: 1
+
+Rate.Quest.Money.Reward = 1
+Rate.Quest.Money.Max.Level.Reward = 1
+
+#
# Rate.RepairCost
# Description: Repair cost rate.
# Default: 1