diff options
Diffstat (limited to 'src')
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 |
