From e66460dad668a173679199a4b0cd9aff8435fe35 Mon Sep 17 00:00:00 2001 From: Nyeriah Date: Fri, 26 Dec 2014 13:12:00 -0200 Subject: Scripts/Oculus: Implement a couple of missing texts (cherry picked from commit 63c1e265aace363a1d889b1621c0cc3a9263e956) --- .../Northrend/Nexus/Oculus/instance_oculus.cpp | 26 ++++++++++++++++++++++ src/server/scripts/Northrend/Nexus/Oculus/oculus.h | 12 ++++++++++ 2 files changed, 38 insertions(+) (limited to 'src') diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp index 0665bfd240c..ed902dba260 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp @@ -192,6 +192,7 @@ class instance_oculus : public InstanceMapScript FreeDragons(); if (Creature* varos = instance->GetCreature(VarosGUID)) varos->SetPhaseMask(1, true); + events.ScheduleEvent(EVENT_VAROS_INTRO, 15000); } break; case DATA_VAROS: @@ -209,6 +210,7 @@ class instance_oculus : public InstanceMapScript { eregos->SetPhaseMask(1, true); GreaterWhelps(); + events.ScheduleEvent(EVENT_EREGOS_INTRO, 5000); } } break; @@ -267,6 +269,28 @@ class instance_oculus : public InstanceMapScript } } + void Update(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_VAROS_INTRO: + if (Creature* varos = instance->GetCreature(VarosGUID)) + varos->AI()->Talk(SAY_VAROS_INTRO_TEXT); + break; + case EVENT_EREGOS_INTRO: + if (Creature* eregos = instance->GetCreature(EregosGUID)) + eregos->AI()->Talk(SAY_EREGOS_INTRO_TEXT); + break; + default: + break; + } + } + } + void GreaterWhelps() { for (ObjectGuid guid : GreaterWhelpList) @@ -289,6 +313,8 @@ class instance_oculus : public InstanceMapScript ObjectGuid EregosCacheGUID; GuidList GreaterWhelpList; + + EventMap events; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.h b/src/server/scripts/Northrend/Nexus/Oculus/oculus.h index 268cdb54e3e..d1144df9486 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.h +++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.h @@ -79,6 +79,18 @@ enum OculusSpells SPELL_DEATH_SPELL = 50415 }; +enum InstanceTexts +{ + SAY_EREGOS_INTRO_TEXT = 0, + SAY_VAROS_INTRO_TEXT = 4 +}; + +enum InstanceEvents +{ + EVENT_VAROS_INTRO = 1, + EVENT_EREGOS_INTRO +}; + enum Misc { POINT_MOVE_OUT = 1 -- cgit v1.2.3 From 6f8a7be1200465ef3a309c0d2530d7570e99f85a Mon Sep 17 00:00:00 2001 From: Nyeriah Date: Fri, 26 Dec 2014 16:27:25 -0200 Subject: Scripts/Commands: Fix a conversion loss at the mute history command (cherry picked from commit 5d4f26d82028823f4672e370deaf0f6069fb225f) --- src/server/scripts/Commands/cs_misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 5a99d30100b..674560f2500 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1978,7 +1978,7 @@ public: static bool HandleMuteInfoHelper(uint32 accountId, char const* accountName, ChatHandler *handler) { PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO); - stmt->setUInt16(0, accountId); + stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) -- cgit v1.2.3 From ae681a96ccf6ce746c2365b993681ec71ff632a7 Mon Sep 17 00:00:00 2001 From: AriDEV Date: Sat, 27 Dec 2014 01:55:27 +0000 Subject: Server/Currency: Implement Apexis Crystals --- src/server/game/DataStores/DBCEnums.h | 1 + src/server/game/Entities/Player/Player.cpp | 9 +++++++++ src/server/game/World/World.cpp | 14 ++++++++++++++ src/server/game/World/World.h | 2 ++ src/server/worldserver/worldserver.conf.dist | 16 ++++++++++++++++ 5 files changed, 42 insertions(+) (limited to 'src') diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 9aefb440d98..3187b5f9f77 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -611,6 +611,7 @@ enum CurrencyTypes CURRENCY_TYPE_VALOR_POINTS = 396, CURRENCY_TYPE_CONQUEST_META_ARENA = 483, CURRENCY_TYPE_CONQUEST_META_RBG = 484, + CURRENCY_TYPE_APEXIS_CRYSTALS = 823, }; #endif diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 367f1f57d3a..9129aca8078 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1039,6 +1039,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac SetUInt32Value(PLAYER_FIELD_COINAGE, sWorld->getIntConfig(CONFIG_START_PLAYER_MONEY)); SetCurrency(CURRENCY_TYPE_HONOR_POINTS, sWorld->getIntConfig(CONFIG_CURRENCY_START_HONOR_POINTS)); + SetCurrency(CURRENCY_TYPE_APEXIS_CRYSTALS, sWorld->getIntConfig(CONFIG_CURRENCY_START_APEXIS_CRYSTALS)); SetCurrency(CURRENCY_TYPE_JUSTICE_POINTS, sWorld->getIntConfig(CONFIG_CURRENCY_START_JUSTICE_POINTS)); SetCurrency(CURRENCY_TYPE_CONQUEST_POINTS, sWorld->getIntConfig(CONFIG_CURRENCY_START_CONQUEST_POINTS)); @@ -7302,6 +7303,7 @@ uint32 Player::GetCurrencyWeekCap(CurrencyTypesEntry const* currency) const uint32 Player::GetCurrencyTotalCap(CurrencyTypesEntry const* currency) const { + // @TODO: Possibly use caps from CurrencyTypes.dbc uint32 cap = currency->MaxQty; switch (currency->ID) @@ -7313,6 +7315,13 @@ uint32 Player::GetCurrencyTotalCap(CurrencyTypesEntry const* currency) const cap = honorcap; break; } + case CURRENCY_TYPE_APEXIS_CRYSTALS: + { + uint32 apexiscap = sWorld->getIntConfig(CONFIG_CURRENCY_MAX_APEXIS_CRYSTALS); + if (apexiscap > 0) + cap = apexiscap; + break; + } case CURRENCY_TYPE_JUSTICE_POINTS: { uint32 justicecap = sWorld->getIntConfig(CONFIG_CURRENCY_MAX_JUSTICE_POINTS); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index eddad11e593..5c8706da09c 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -851,6 +851,20 @@ void World::LoadConfigSettings(bool reload) } m_int_configs[CONFIG_CURRENCY_MAX_HONOR_POINTS] *= 100; //precision mod + m_int_configs[CONFIG_CURRENCY_START_APEXIS_CRYSTALS] = sConfigMgr->GetIntDefault("Currency.StartApexisCrystals", 0); + if (int32(m_int_configs[CONFIG_CURRENCY_START_APEXIS_CRYSTALS]) < 0) + { + TC_LOG_ERROR("server.loading", "Currency.StartApexisCrystals (%i) must be >= 0, set to default 0.", m_int_configs[CONFIG_CURRENCY_START_APEXIS_CRYSTALS]); + m_int_configs[CONFIG_CURRENCY_START_APEXIS_CRYSTALS] = 0; + } + m_int_configs[CONFIG_CURRENCY_MAX_APEXIS_CRYSTALS] = sConfigMgr->GetIntDefault("Currency.MaxApexisCrystals", 20000); + if (int32(m_int_configs[CONFIG_CURRENCY_MAX_APEXIS_CRYSTALS]) < 0) + { + TC_LOG_ERROR("server.loading", "Currency.MaxApexisCrystals (%i) can't be negative. Set to default 20000.", m_int_configs[CONFIG_CURRENCY_MAX_APEXIS_CRYSTALS]); + m_int_configs[CONFIG_CURRENCY_MAX_APEXIS_CRYSTALS] = 20000; + } + m_int_configs[CONFIG_CURRENCY_MAX_APEXIS_CRYSTALS] *= 100; //precision mod + m_int_configs[CONFIG_CURRENCY_START_JUSTICE_POINTS] = sConfigMgr->GetIntDefault("Currency.StartJusticePoints", 0); if (int32(m_int_configs[CONFIG_CURRENCY_START_JUSTICE_POINTS]) < 0) { diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 7f583da894b..8f77ab786c7 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -229,6 +229,8 @@ enum WorldIntConfigs CONFIG_START_PLAYER_LEVEL, CONFIG_START_HEROIC_PLAYER_LEVEL, CONFIG_START_PLAYER_MONEY, + CONFIG_CURRENCY_START_APEXIS_CRYSTALS, + CONFIG_CURRENCY_MAX_APEXIS_CRYSTALS, CONFIG_CURRENCY_START_JUSTICE_POINTS, CONFIG_CURRENCY_MAX_JUSTICE_POINTS, CONFIG_CURRENCY_START_HONOR_POINTS, diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 11c081bea44..3e3a04aee55 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3249,6 +3249,22 @@ Currency.StartHonorPoints = 0 Currency.MaxHonorPoints = 4000 +# +# Currency.StartApexisCrystals +# Amount of Apexis Crystals that new players will start with +# Default: 0 (with precision) +# + +Currency.StartApexisCrystals = 0 + +# +# Currency.MaxApexisCrystals +# Amount Apexis Crystals a player can have +# Default: 20000 +# + +Currency.MaxApexisCrystals = 20000 + # # Currency.StartJusticePoints # Amount of justice points that new players will start with -- cgit v1.2.3 From 8d2e230419b2d650201d8fbcb98b0e5f7afb830e Mon Sep 17 00:00:00 2001 From: Gacko Date: Sat, 27 Dec 2014 11:58:10 +0100 Subject: ItemTemplate: Fix warning about missing cases. --- src/server/game/Entities/Item/ItemTemplate.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index 8f88feec644..ddf9dc65bec 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -670,6 +670,8 @@ struct ItemTemplate case INVTYPE_SHIELD: case INVTYPE_HOLDABLE: return true; + default: + break; } switch (GetClass()) -- cgit v1.2.3 From cf893351773c9193b4860a9c54e825f2138773a4 Mon Sep 17 00:00:00 2001 From: Gacko Date: Sat, 27 Dec 2014 13:57:36 +0100 Subject: Fix non pch build --- src/server/game/DataStores/DB2Stores.h | 1 + src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp | 1 + src/server/shared/DataStores/DB2StorageLoader.h | 2 ++ 3 files changed, 4 insertions(+) (limited to 'src') diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 01b28e6ec72..878498a94da 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -22,6 +22,7 @@ #include "DB2Structure.h" #include #include +#include "SharedDefines.h" extern DB2Storage sBroadcastTextStore; extern DB2Storage sHolidaysStore; diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp index 1df5f5eac8f..c12b0889f9d 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp @@ -19,6 +19,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "nexus.h" +#include "GameEventMgr.h" enum Spells { diff --git a/src/server/shared/DataStores/DB2StorageLoader.h b/src/server/shared/DataStores/DB2StorageLoader.h index 4254fcc1121..cc9bfa76b5c 100644 --- a/src/server/shared/DataStores/DB2StorageLoader.h +++ b/src/server/shared/DataStores/DB2StorageLoader.h @@ -21,6 +21,8 @@ #include "Define.h" #include "Utilities/ByteConverter.h" #include +#include +#include "Common.h" class DB2FileLoader { -- cgit v1.2.3 From 584672556c5d485b93ff805f52be548a813581ab Mon Sep 17 00:00:00 2001 From: MrSmite Date: Fri, 14 Nov 2014 16:38:12 -0500 Subject: Fix spell cooldown for guardian pets (cherry picked from commit 54cc8adac5db101f427b76373ce79d587f7e5332) --- src/server/game/Spells/Spell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 66e67d0f09e..9daf32188df 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3555,7 +3555,7 @@ void Spell::SendSpellCooldown() { // Handle pet cooldowns here if needed instead of in PetAI to avoid hidden cooldown restarts Creature* _creature = m_caster->ToCreature(); - if (_creature && _creature->IsPet()) + if (_creature && (_creature->IsPet() || _creature->IsGuardian())) _creature->AddCreatureSpellCooldown(m_spellInfo->Id); return; -- cgit v1.2.3 From 959ea73734f510d2761bd8f19ff95ce1fc093ba5 Mon Sep 17 00:00:00 2001 From: jackpoz Date: Sat, 27 Dec 2014 15:48:29 +0000 Subject: Core/NetworkIO: Skip AntiDoS checks for queued packets (cherry picked from commit d8c3115bbd1b544d6eca5d9aae3dfbb547353703) --- src/server/game/Server/WorldSession.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 3a9f5e70204..350291c2b4e 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -334,9 +334,6 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) while (m_Socket[CONNECTION_TYPE_REALM] && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { - if (!AntiDOS.EvaluateOpcode(*packet, currentTime)) - KickPlayer(); - ClientOpcodeHandler const* opHandle = opcodeTable[static_cast(packet->GetOpcode())]; try { @@ -361,7 +358,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) "Player is currently not in world yet.", GetOpcodeNameForLogging(static_cast(packet->GetOpcode())).c_str()); } } - else if (_player->IsInWorld()) + else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime)) { sScriptMgr->OnPacketReceive(this, *packet); opHandle->Call(this, *packet); @@ -373,7 +370,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT", "the player has not logged in yet and not recently logout"); - else + else if (AntiDOS.EvaluateOpcode(*packet, currentTime)) { // not expected _player or must checked in packet hanlder sScriptMgr->OnPacketReceive(this, *packet); @@ -386,7 +383,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet"); else if (_player->IsInWorld()) LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world"); - else + else if(AntiDOS.EvaluateOpcode(*packet, currentTime)) { sScriptMgr->OnPacketReceive(this, *packet); opHandle->Call(this, *packet); @@ -406,9 +403,12 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (packet->GetOpcode() == CMSG_CHAR_ENUM) m_playerRecentlyLogout = false; - sScriptMgr->OnPacketReceive(this, *packet); - opHandle->Call(this, *packet); - LogUnprocessedTail(packet); + if (AntiDOS.EvaluateOpcode(*packet, currentTime)) + { + sScriptMgr->OnPacketReceive(this, *packet); + opHandle->Call(this, *packet); + LogUnprocessedTail(packet); + } break; case STATUS_NEVER: TC_LOG_ERROR("network.opcode", "Received not allowed opcode %s from %s", GetOpcodeNameForLogging(static_cast(packet->GetOpcode())).c_str() @@ -1170,8 +1170,11 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co case POLICY_LOG: return true; case POLICY_KICK: + { TC_LOG_INFO("network", "AntiDOS: Player kicked!"); + Session->KickPlayer(); return false; + } case POLICY_BAN: { BanMode bm = (BanMode)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANMODE); @@ -1185,7 +1188,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co } sWorld->BanAccount(bm, nameOrIp, duration, "DOS (Packet Flooding/Spoofing", "Server: AutoDOS"); TC_LOG_INFO("network", "AntiDOS: Player automatically banned for %u seconds.", duration); - + Session->KickPlayer(); return false; } default: // invalid policy -- cgit v1.2.3 From c8e555f65867b67840013c48f4665aa08ccc6392 Mon Sep 17 00:00:00 2001 From: mthsena Date: Sat, 27 Dec 2014 18:10:47 +0000 Subject: Core/RBAC: Add two side trade to RBAC (cherry-picked from commit 3ee2f0d2bf9d5f859c8022ca49f1889c35584ffe) --- sql/base/auth_database.sql | 6 +++--- sql/updates/auth/2014_12_27_00_auth.sql | 9 +++++++++ src/server/game/Accounts/RBAC.h | 1 + src/server/game/Handlers/TradeHandler.cpp | 4 +++- 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 sql/updates/auth/2014_12_27_00_auth.sql (limited to 'src') diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 34b55fa2065..28b6f4b94bd 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -496,7 +496,7 @@ CREATE TABLE `rbac_linked_permissions` ( LOCK TABLES `rbac_linked_permissions` WRITE; /*!40000 ALTER TABLE `rbac_linked_permissions` DISABLE KEYS */; -INSERT INTO `rbac_linked_permissions` VALUES (192,21),(192,42),(192,43),(192,193),(192,196),(192,778),(192,779),(192,780),(192,781),(192,782),(192,783),(192,784),(192,785),(192,786),(192,787),(192,788),(192,789),(192,790),(192,791),(192,792),(192,793),(192,794),(193,48),(193,194),(193,197),(194,1),(194,2),(194,11),(194,13),(194,14),(194,15),(194,16),(194,17),(194,18),(194,19),(194,20),(194,22),(194,23),(194,25),(194,26),(194,27),(194,28),(194,29),(194,30),(194,31),(194,32),(194,33),(194,34),(194,35),(194,36),(194,37),(194,38),(194,39),(194,40),(194,41),(194,44),(194,46),(194,47),(194,195),(194,198),(194,632),(194,798),(195,3),(195,4),(195,5),(195,6),(195,24),(195,49),(195,199),(196,200),(196,201),(196,208),(196,212),(196,213),(196,214),(196,215),(196,216),(196,226),(196,227),(196,230),(196,231),(196,233),(196,234),(196,235),(196,238),(196,239),(196,240),(196,241),(196,242),(196,243),(196,244),(196,245),(196,246),(196,247),(196,248),(196,249),(196,250),(196,251),(196,252),(196,253),(196,254),(196,255),(196,256),(196,257),(196,258),(196,259),(196,260),(196,261),(196,262),(196,264),(196,265),(196,266),(196,267),(196,268),(196,269),(196,270),(196,271),(196,272),(196,279),(196,280),(196,283),(196,287),(196,288),(196,289),(196,290),(196,291),(196,292),(196,293),(196,294),(196,295),(196,296),(196,297),(196,298),(196,299),(196,302),(196,303),(196,304),(196,305),(196,306),(196,307),(196,308),(196,309),(196,310),(196,313),(196,314),(196,319),(196,320),(196,321),(196,322),(196,323),(196,324),(196,325),(196,326),(196,327),(196,328),(196,329),(196,330),(196,331),(196,332),(196,333),(196,334),(196,335),(196,336),(196,337),(196,338),(196,339),(196,340),(196,341),(196,342),(196,343),(196,344),(196,345),(196,346),(196,347),(196,348),(196,349),(196,350),(196,351),(196,352),(196,353),(196,354),(196,355),(196,356),(196,357),(196,358),(196,359),(196,360),(196,361),(196,362),(196,363),(196,364),(196,365),(196,366),(196,373),(196,375),(196,400),(196,401),(196,402),(196,403),(196,404),(196,405),(196,406),(196,407),(196,417),(196,418),(196,419),(196,420),(196,421),(196,422),(196,423),(196,424),(196,425),(196,426),(196,427),(196,428),(196,429),(196,434),(196,435),(196,436),(196,437),(196,438),(196,439),(196,440),(196,441),(196,442),(196,443),(196,444),(196,445),(196,446),(196,447),(196,448),(196,449),(196,450),(196,451),(196,452),(196,453),(196,454),(196,455),(196,456),(196,457),(196,458),(196,459),(196,461),(196,463),(196,464),(196,465),(196,472),(196,473),(196,474),(196,475),(196,476),(196,477),(196,478),(196,488),(196,489),(196,491),(196,492),(196,493),(196,495),(196,497),(196,498),(196,499),(196,500),(196,502),(196,503),(196,505),(196,508),(196,511),(196,513),(196,514),(196,516),(196,519),(196,522),(196,523),(196,526),(196,527),(196,529),(196,530),(196,533),(196,535),(196,536),(196,537),(196,538),(196,539),(196,540),(196,541),(196,556),(196,581),(196,582),(196,592),(196,593),(196,596),(196,602),(196,603),(196,604),(196,605),(196,606),(196,607),(196,608),(196,609),(196,610),(196,611),(196,612),(196,613),(196,615),(196,616),(196,617),(196,618),(196,619),(196,620),(196,621),(196,622),(196,623),(196,624),(196,625),(196,626),(196,627),(196,628),(196,629),(196,630),(196,631),(196,633),(196,634),(196,635),(196,636),(196,637),(196,638),(196,639),(196,640),(196,641),(196,642),(196,643),(196,644),(196,645),(196,646),(196,647),(196,648),(196,649),(196,650),(196,651),(196,652),(196,653),(196,654),(196,655),(196,656),(196,657),(196,658),(196,659),(196,660),(196,661),(196,662),(196,663),(196,664),(196,665),(196,666),(196,667),(196,668),(196,669),(196,670),(196,671),(196,672),(196,673),(196,674),(196,675),(196,676),(196,677),(196,678),(196,679),(196,680),(196,681),(196,682),(196,683),(196,684),(196,685),(196,686),(196,687),(196,688),(196,689),(196,690),(196,691),(196,693),(196,694),(196,695),(196,696),(196,697),(196,698),(196,699),(196,700),(196,701),(196,702),(196,703),(196,704),(196,705),(196,706),(196,707),(196,708),(196,709),(196,710),(196,711),(196,712),(196,713),(196,714),(196,715),(196,716),(196,717),(196,718),(196,719),(196,721),(196,722),(196,723),(196,724),(196,725),(196,726),(196,727),(196,728),(196,729),(196,730),(196,733),(196,734),(196,735),(196,736),(196,738),(196,739),(196,748),(196,753),(196,757),(196,773),(196,777),(197,232),(197,236),(197,237),(197,273),(197,274),(197,275),(197,276),(197,277),(197,284),(197,285),(197,286),(197,301),(197,311),(197,387),(197,388),(197,389),(197,390),(197,391),(197,392),(197,393),(197,394),(197,395),(197,396),(197,397),(197,398),(197,399),(197,479),(197,480),(197,481),(197,482),(197,485),(197,486),(197,487),(197,494),(197,506),(197,509),(197,510),(197,517),(197,518),(197,521),(197,542),(197,543),(197,550),(197,558),(197,568),(197,571),(197,572),(197,573),(197,574),(197,575),(197,576),(197,577),(197,578),(197,579),(197,580),(197,583),(197,584),(197,585),(197,586),(197,587),(197,588),(197,589),(197,590),(197,591),(197,594),(197,595),(197,601),(197,743),(197,750),(197,758),(197,761),(197,762),(197,763),(197,764),(197,765),(197,766),(197,767),(197,768),(197,769),(197,770),(197,771),(197,772),(197,774),(198,218),(198,300),(198,312),(198,315),(198,316),(198,317),(198,318),(198,367),(198,368),(198,369),(198,370),(198,371),(198,372),(198,374),(198,376),(198,377),(198,378),(198,379),(198,380),(198,381),(198,382),(198,383),(198,384),(198,385),(198,386),(198,408),(198,409),(198,410),(198,411),(198,412),(198,413),(198,414),(198,415),(198,416),(198,430),(198,431),(198,432),(198,433),(198,462),(198,466),(198,467),(198,468),(198,469),(198,470),(198,471),(198,483),(198,484),(198,490),(198,504),(198,512),(198,515),(198,520),(198,524),(198,528),(198,531),(198,532),(198,544),(198,545),(198,546),(198,547),(198,548),(198,549),(198,551),(198,552),(198,553),(198,554),(198,555),(198,557),(198,559),(198,560),(198,561),(198,562),(198,563),(198,564),(198,565),(198,566),(198,567),(198,569),(198,570),(198,597),(198,598),(198,599),(198,600),(198,737),(198,740),(198,741),(198,742),(198,744),(198,745),(198,746),(198,747),(198,749),(198,751),(198,752),(198,754),(198,755),(198,756),(198,759),(198,760),(199,207),(199,209),(199,210),(199,211),(199,217),(199,221),(199,222),(199,223),(199,225),(199,263),(199,496),(199,501),(199,507),(199,525),(199,534),(199,797); +INSERT INTO `rbac_linked_permissions` VALUES (192,21),(192,42),(192,43),(192,193),(192,196),(192,778),(192,779),(192,780),(192,781),(192,782),(192,783),(192,784),(192,785),(192,786),(192,787),(192,788),(192,789),(192,790),(192,791),(192,792),(192,793),(192,794),(193,48),(193,194),(193,197),(194,1),(194,2),(194,11),(194,13),(194,14),(194,15),(194,16),(194,17),(194,18),(194,19),(194,20),(194,22),(194,23),(194,25),(194,26),(194,27),(194,28),(194,29),(194,30),(194,31),(194,32),(194,33),(194,34),(194,35),(194,36),(194,37),(194,38),(194,39),(194,40),(194,41),(194,44),(194,46),(194,47),(194,51),(194,195),(194,198),(194,632),(194,798),(195,3),(195,4),(195,5),(195,6),(195,24),(195,49),(195,199),(196,200),(196,201),(196,208),(196,212),(196,213),(196,214),(196,215),(196,216),(196,226),(196,227),(196,230),(196,231),(196,233),(196,234),(196,235),(196,238),(196,239),(196,240),(196,241),(196,242),(196,243),(196,244),(196,245),(196,246),(196,247),(196,248),(196,249),(196,250),(196,251),(196,252),(196,253),(196,254),(196,255),(196,256),(196,257),(196,258),(196,259),(196,260),(196,261),(196,262),(196,264),(196,265),(196,266),(196,267),(196,268),(196,269),(196,270),(196,271),(196,272),(196,279),(196,280),(196,283),(196,287),(196,288),(196,289),(196,290),(196,291),(196,292),(196,293),(196,294),(196,295),(196,296),(196,297),(196,298),(196,299),(196,302),(196,303),(196,304),(196,305),(196,306),(196,307),(196,308),(196,309),(196,310),(196,313),(196,314),(196,319),(196,320),(196,321),(196,322),(196,323),(196,324),(196,325),(196,326),(196,327),(196,328),(196,329),(196,330),(196,331),(196,332),(196,333),(196,334),(196,335),(196,336),(196,337),(196,338),(196,339),(196,340),(196,341),(196,342),(196,343),(196,344),(196,345),(196,346),(196,347),(196,348),(196,349),(196,350),(196,351),(196,352),(196,353),(196,354),(196,355),(196,356),(196,357),(196,358),(196,359),(196,360),(196,361),(196,362),(196,363),(196,364),(196,365),(196,366),(196,373),(196,375),(196,400),(196,401),(196,402),(196,403),(196,404),(196,405),(196,406),(196,407),(196,417),(196,418),(196,419),(196,420),(196,421),(196,422),(196,423),(196,424),(196,425),(196,426),(196,427),(196,428),(196,429),(196,434),(196,435),(196,436),(196,437),(196,438),(196,439),(196,440),(196,441),(196,442),(196,443),(196,444),(196,445),(196,446),(196,447),(196,448),(196,449),(196,450),(196,451),(196,452),(196,453),(196,454),(196,455),(196,456),(196,457),(196,458),(196,459),(196,461),(196,463),(196,464),(196,465),(196,472),(196,473),(196,474),(196,475),(196,476),(196,477),(196,478),(196,488),(196,489),(196,491),(196,492),(196,493),(196,495),(196,497),(196,498),(196,499),(196,500),(196,502),(196,503),(196,505),(196,508),(196,511),(196,513),(196,514),(196,516),(196,519),(196,522),(196,523),(196,526),(196,527),(196,529),(196,530),(196,533),(196,535),(196,536),(196,537),(196,538),(196,539),(196,540),(196,541),(196,556),(196,581),(196,582),(196,592),(196,593),(196,596),(196,602),(196,603),(196,604),(196,605),(196,606),(196,607),(196,608),(196,609),(196,610),(196,611),(196,612),(196,613),(196,615),(196,616),(196,617),(196,618),(196,619),(196,620),(196,621),(196,622),(196,623),(196,624),(196,625),(196,626),(196,627),(196,628),(196,629),(196,630),(196,631),(196,633),(196,634),(196,635),(196,636),(196,637),(196,638),(196,639),(196,640),(196,641),(196,642),(196,643),(196,644),(196,645),(196,646),(196,647),(196,648),(196,649),(196,650),(196,651),(196,652),(196,653),(196,654),(196,655),(196,656),(196,657),(196,658),(196,659),(196,660),(196,661),(196,662),(196,663),(196,664),(196,665),(196,666),(196,667),(196,668),(196,669),(196,670),(196,671),(196,672),(196,673),(196,674),(196,675),(196,676),(196,677),(196,678),(196,679),(196,680),(196,681),(196,682),(196,683),(196,684),(196,685),(196,686),(196,687),(196,688),(196,689),(196,690),(196,691),(196,693),(196,694),(196,695),(196,696),(196,697),(196,698),(196,699),(196,700),(196,701),(196,702),(196,703),(196,704),(196,705),(196,706),(196,707),(196,708),(196,709),(196,710),(196,711),(196,712),(196,713),(196,714),(196,715),(196,716),(196,717),(196,718),(196,719),(196,721),(196,722),(196,723),(196,724),(196,725),(196,726),(196,727),(196,728),(196,729),(196,730),(196,733),(196,734),(196,735),(196,736),(196,738),(196,739),(196,748),(196,753),(196,757),(196,773),(196,777),(197,232),(197,236),(197,237),(197,273),(197,274),(197,275),(197,276),(197,277),(197,284),(197,285),(197,286),(197,301),(197,311),(197,387),(197,388),(197,389),(197,390),(197,391),(197,392),(197,393),(197,394),(197,395),(197,396),(197,397),(197,398),(197,399),(197,479),(197,480),(197,481),(197,482),(197,485),(197,486),(197,487),(197,494),(197,506),(197,509),(197,510),(197,517),(197,518),(197,521),(197,542),(197,543),(197,550),(197,558),(197,568),(197,571),(197,572),(197,573),(197,574),(197,575),(197,576),(197,577),(197,578),(197,579),(197,580),(197,583),(197,584),(197,585),(197,586),(197,587),(197,588),(197,589),(197,590),(197,591),(197,594),(197,595),(197,601),(197,743),(197,750),(197,758),(197,761),(197,762),(197,763),(197,764),(197,765),(197,766),(197,767),(197,768),(197,769),(197,770),(197,771),(197,772),(197,774),(198,218),(198,300),(198,312),(198,315),(198,316),(198,317),(198,318),(198,367),(198,368),(198,369),(198,370),(198,371),(198,372),(198,374),(198,376),(198,377),(198,378),(198,379),(198,380),(198,381),(198,382),(198,383),(198,384),(198,385),(198,386),(198,408),(198,409),(198,410),(198,411),(198,412),(198,413),(198,414),(198,415),(198,416),(198,430),(198,431),(198,432),(198,433),(198,462),(198,466),(198,467),(198,468),(198,469),(198,470),(198,471),(198,483),(198,484),(198,490),(198,504),(198,512),(198,515),(198,520),(198,524),(198,528),(198,531),(198,532),(198,544),(198,545),(198,546),(198,547),(198,548),(198,549),(198,551),(198,552),(198,553),(198,554),(198,555),(198,557),(198,559),(198,560),(198,561),(198,562),(198,563),(198,564),(198,565),(198,566),(198,567),(198,569),(198,570),(198,597),(198,598),(198,599),(198,600),(198,737),(198,740),(198,741),(198,742),(198,744),(198,745),(198,746),(198,747),(198,749),(198,751),(198,752),(198,754),(198,755),(198,756),(198,759),(198,760),(199,207),(199,209),(199,210),(199,211),(199,217),(199,221),(199,222),(199,223),(199,225),(199,263),(199,496),(199,501),(199,507),(199,525),(199,534),(199,797); /*!40000 ALTER TABLE `rbac_linked_permissions` ENABLE KEYS */; UNLOCK TABLES; @@ -520,7 +520,7 @@ CREATE TABLE `rbac_permissions` ( LOCK TABLES `rbac_permissions` WRITE; /*!40000 ALTER TABLE `rbac_permissions` DISABLE KEYS */; -INSERT INTO `rbac_permissions` VALUES (1,'Instant logout'),(2,'Skip Queue'),(3,'Join Normal Battleground'),(4,'Join Random Battleground'),(5,'Join Arenas'),(6,'Join Dungeon Finder'),(11,'Log GM trades'),(13,'Skip Instance required bosses check'),(14,'Skip character creation team mask check'),(15,'Skip character creation class mask check'),(16,'Skip character creation race mask check'),(17,'Skip character creation reserved name check'),(18,'Skip character creation heroic min level check'),(19,'Skip needed requirements to use channel check'),(20,'Skip disable map check'),(21,'Skip reset talents when used more than allowed check'),(22,'Skip spam chat check'),(23,'Skip over-speed ping check'),(24,'Two side faction characters on the same account'),(25,'Allow say chat between factions'),(26,'Allow channel chat between factions'),(27,'Two side mail interaction'),(28,'See two side who list'),(29,'Add friends of other faction'),(30,'Save character without delay with .save command'),(31,'Use params with .unstuck command'),(32,'Can be assigned tickets with .assign ticket command'),(33,'Notify if a command was not found'),(34,'Check if should appear in list using .gm ingame command'),(35,'See all security levels with who command'),(36,'Filter whispers'),(37,'Use staff badge in chat'),(38,'Resurrect with full Health Points'),(39,'Restore saved gm setting states'),(40,'Allows to add a gm to friend list'),(41,'Use Config option START_GM_LEVEL to assign new character level'),(42,'Allows to use CMSG_WORLD_TELEPORT opcode'),(43,'Allows to use CMSG_WHOIS opcode'),(44,'Receive global GM messages/texts'),(45,'Join channels without announce'),(46,'Change channel settings without being channel moderator'),(47,'Enables lower security than target check'),(48,'Enable IP, Last Login and EMail output in pinfo'),(49,'Forces to enter the email for confirmation on password change'),(50,'Allow user to check his own email with .account'),(192,'Role: Sec Level Administrator'),(193,'Role: Sec Level Gamemaster'),(194,'Role: Sec Level Moderator'),(195,'Role: Sec Level Player'),(196,'Role: Administrator Commands'),(197,'Role: Gamemaster Commands'),(198,'Role: Moderator Commands'),(199,'Role: Player Commands'),(200,'Command: rbac'),(201,'Command: rbac account'),(202,'Command: rbac account list'),(203,'Command: rbac account grant'),(204,'Command: rbac account deny'),(205,'Command: rbac account revoke'),(206,'Command: rbac list'),(207,'Command: battlenetaccount'),(208,'Command: battlenetaccount create'),(209,'Command: battlenetaccount lock country'),(210,'Command: battlenetaccount lock ip'),(211,'Command: battlenetaccount password'),(212,'Command: battlenetaccount set'),(213,'Command: battlenetaccount set password'),(214,'Command: bnetaccount link'),(215,'Command: bnetaccount unlink'),(216,'Command: bnetaccount gameaccountcreate'),(217,'Command: account'),(218,'Command: account addon'),(219,'Command: account create'),(220,'Command: account delete'),(221,'Command: account lock'),(222,'Command: account lock country'),(223,'Command: account lock ip'),(224,'Command: account onlinelist'),(225,'Command: account password'),(226,'Command: account set'),(227,'Command: account set addon'),(228,'Command: account set gmlevel'),(229,'Command: account set password'),(230,'Command: achievement'),(231,'Command: achievement add'),(232,'Command: arena'),(233,'Command: arena captain'),(234,'Command: arena create'),(235,'Command: arena disband'),(236,'Command: arena info'),(237,'Command: arena lookup'),(238,'Command: arena rename'),(239,'Command: ban'),(240,'Command: ban account'),(241,'Command: ban character'),(242,'Command: ban ip'),(243,'Command: ban playeraccount'),(244,'Command: baninfo'),(245,'Command: baninfo account'),(246,'Command: baninfo character'),(247,'Command: baninfo ip'),(248,'Command: banlist'),(249,'Command: banlist account'),(250,'Command: banlist character'),(251,'Command: banlist ip'),(252,'Command: unban'),(253,'Command: unban account'),(254,'Command: unban character'),(255,'Command: unban ip'),(256,'Command: unban playeraccount'),(257,'Command: bf'),(258,'Command: bf start'),(259,'Command: bf stop'),(260,'Command: bf switch'),(261,'Command: bf timer'),(262,'Command: bf enable'),(263,'Command: account email'),(264,'Command: account set sec'),(265,'Command: account set sec email'),(266,'Command: account set sec regmail'),(267,'Command: cast'),(268,'Command: cast back'),(269,'Command: cast dist'),(270,'Command: cast self'),(271,'Command: cast target'),(272,'Command: cast dest'),(273,'Command: character'),(274,'Command: character customize'),(275,'Command: character changefaction'),(276,'Command: character changerace'),(277,'Command: character deleted'),(279,'Command: character deleted list'),(280,'Command: character deleted restore'),(283,'Command: character level'),(284,'Command: character rename'),(285,'Command: character reputation'),(286,'Command: character titles'),(287,'Command: levelup'),(288,'Command: pdump'),(289,'Command: pdump load'),(290,'Command: pdump write'),(291,'Command: cheat'),(292,'Command: cheat casttime'),(293,'Command: cheat cooldown'),(294,'Command: cheat explore'),(295,'Command: cheat god'),(296,'Command: cheat power'),(297,'Command: cheat status'),(298,'Command: cheat taxi'),(299,'Command: cheat waterwalk'),(300,'Command: debug'),(301,'Command: debug anim'),(302,'Command: debug areatriggers'),(303,'Command: debug arena'),(304,'Command: debug bg'),(305,'Command: debug entervehicle'),(306,'Command: debug getitemstate'),(307,'Command: debug getitemvalue'),(308,'Command: debug getvalue'),(309,'Command: debug hostil'),(310,'Command: debug itemexpire'),(311,'Command: debug lootrecipient'),(312,'Command: debug los'),(313,'Command: debug mod32value'),(314,'Command: debug moveflags'),(315,'Command: debug play'),(316,'Command: debug play cinematics'),(317,'Command: debug play movie'),(318,'Command: debug play sound'),(319,'Command: debug send'),(320,'Command: debug send buyerror'),(321,'Command: debug send channelnotify'),(322,'Command: debug send chatmessage'),(323,'Command: debug send equiperror'),(324,'Command: debug send largepacket'),(325,'Command: debug send opcode'),(326,'Command: debug send qinvalidmsg'),(327,'Command: debug send qpartymsg'),(328,'Command: debug send sellerror'),(329,'Command: debug send setphaseshift'),(330,'Command: debug send spellfail'),(331,'Command: debug setaurastate'),(332,'Command: debug setbit'),(333,'Command: debug setitemvalue'),(334,'Command: debug setvalue'),(335,'Command: debug setvid'),(336,'Command: debug spawnvehicle'),(337,'Command: debug threat'),(338,'Command: debug update'),(339,'Command: debug uws'),(340,'Command: wpgps'),(341,'Command: deserter'),(342,'Command: deserter bg'),(343,'Command: deserter bg add'),(344,'Command: deserter bg remove'),(345,'Command: deserter instance'),(346,'Command: deserter instance add'),(347,'Command: deserter instance remove'),(348,'Command: disable'),(349,'Command: disable add'),(350,'Command: disable add achievement_criteria'),(351,'Command: disable add battleground'),(352,'Command: disable add map'),(353,'Command: disable add mmap'),(354,'Command: disable add outdoorpvp'),(355,'Command: disable add quest'),(356,'Command: disable add spell'),(357,'Command: disable add vmap'),(358,'Command: disable remove'),(359,'Command: disable remove achievement_criteria'),(360,'Command: disable remove battleground'),(361,'Command: disable remove map'),(362,'Command: disable remove mmap'),(363,'Command: disable remove outdoorpvp'),(364,'Command: disable remove quest'),(365,'Command: disable remove spell'),(366,'Command: disable remove vmap'),(367,'Command: event'),(368,'Command: event activelist'),(369,'Command: event start'),(370,'Command: event stop'),(371,'Command: gm'),(372,'Command: gm chat'),(373,'Command: gm fly'),(374,'Command: gm ingame'),(375,'Command: gm list'),(376,'Command: gm visible'),(377,'Command: go'),(378,'Command: go creature'),(379,'Command: go graveyard'),(380,'Command: go grid'),(381,'Command: go object'),(382,'Command: go taxinode'),(383,'Command: go ticket'),(384,'Command: go trigger'),(385,'Command: go xyz'),(386,'Command: go zonexy'),(387,'Command: gobject'),(388,'Command: gobject activate'),(389,'Command: gobject add'),(390,'Command: gobject add temp'),(391,'Command: gobject delete'),(392,'Command: gobject info'),(393,'Command: gobject move'),(394,'Command: gobject near'),(395,'Command: gobject set'),(396,'Command: gobject set phase'),(397,'Command: gobject set state'),(398,'Command: gobject target'),(399,'Command: gobject turn'),(400,'debug transport'),(401,'Command: guild'),(402,'Command: guild create'),(403,'Command: guild delete'),(404,'Command: guild invite'),(405,'Command: guild uninvite'),(406,'Command: guild rank'),(407,'Command: guild rename'),(408,'Command: honor'),(409,'Command: honor add'),(410,'Command: honor add kill'),(411,'Command: honor update'),(412,'Command: instance'),(413,'Command: instance listbinds'),(414,'Command: instance unbind'),(415,'Command: instance stats'),(416,'Command: instance savedata'),(417,'Command: learn'),(418,'Command: learn all'),(419,'Command: learn all my'),(420,'Command: learn all my class'),(421,'Command: learn all my pettalents'),(422,'Command: learn all my spells'),(423,'Command: learn all my talents'),(424,'Command: learn all gm'),(425,'Command: learn all crafts'),(426,'Command: learn all default'),(427,'Command: learn all lang'),(428,'Command: learn all recipes'),(429,'Command: unlearn'),(430,'Command: lfg'),(431,'Command: lfg player'),(432,'Command: lfg group'),(433,'Command: lfg queue'),(434,'Command: lfg clean'),(435,'Command: lfg options'),(436,'Command: list'),(437,'Command: list creature'),(438,'Command: list item'),(439,'Command: list object'),(440,'Command: list auras'),(441,'Command: list mail'),(442,'Command: lookup'),(443,'Command: lookup area'),(444,'Command: lookup creature'),(445,'Command: lookup event'),(446,'Command: lookup faction'),(447,'Command: lookup item'),(448,'Command: lookup itemset'),(449,'Command: lookup object'),(450,'Command: lookup quest'),(451,'Command: lookup player'),(452,'Command: lookup player ip'),(453,'Command: lookup player account'),(454,'Command: lookup player email'),(455,'Command: lookup skill'),(456,'Command: lookup spell'),(457,'Command: lookup spell id'),(458,'Command: lookup taxinode'),(459,'Command: lookup tele'),(460,'Command: lookup title'),(461,'Command: lookup map'),(462,'Command: announce'),(463,'Command: channel'),(464,'Command: channel set'),(465,'Command: channel set ownership'),(466,'Command: gmannounce'),(467,'Command: gmnameannounce'),(468,'Command: gmnotify'),(469,'Command: nameannounce'),(470,'Command: notify'),(471,'Command: whispers'),(472,'Command: group'),(473,'Command: group leader'),(474,'Command: group disband'),(475,'Command: group remove'),(476,'Command: group join'),(477,'Command: group list'),(478,'Command: group summon'),(479,'Command: pet'),(480,'Command: pet create'),(481,'Command: pet learn'),(482,'Command: pet unlearn'),(483,'Command: send'),(484,'Command: send items'),(485,'Command: send mail'),(486,'Command: send message'),(487,'Command: send money'),(488,'Command: additem'),(489,'Command: additemset'),(490,'Command: appear'),(491,'Command: aura'),(492,'Command: bank'),(493,'Command: bindsight'),(494,'Command: combatstop'),(495,'Command: cometome'),(496,'Command: commands'),(497,'Command: cooldown'),(498,'Command: damage'),(499,'Command: dev'),(500,'Command: die'),(501,'Command: dismount'),(502,'Command: distance'),(503,'Command: flusharenapoints'),(504,'Command: freeze'),(505,'Command: gps'),(506,'Command: guid'),(507,'Command: help'),(508,'Command: hidearea'),(509,'Command: itemmove'),(510,'Command: kick'),(511,'Command: linkgrave'),(512,'Command: listfreeze'),(513,'Command: maxskill'),(514,'Command: movegens'),(515,'Command: mute'),(516,'Command: neargrave'),(517,'Command: pinfo'),(518,'Command: playall'),(519,'Command: possess'),(520,'Command: recall'),(521,'Command: repairitems'),(522,'Command: respawn'),(523,'Command: revive'),(524,'Command: saveall'),(525,'Command: save'),(526,'Command: setskill'),(527,'Command: showarea'),(528,'Command: summon'),(529,'Command: unaura'),(530,'Command: unbindsight'),(531,'Command: unfreeze'),(532,'Command: unmute'),(533,'Command: unpossess'),(534,'Command: unstuck'),(535,'Command: wchange'),(536,'Command: mmap'),(537,'Command: mmap loadedtiles'),(538,'Command: mmap loc'),(539,'Command: mmap path'),(540,'Command: mmap stats'),(541,'Command: mmap testarea'),(542,'Command: morph'),(543,'Command: demorph'),(544,'Command: modify'),(545,'Command: modify arenapoints'),(546,'Command: modify bit'),(547,'Command: modify drunk'),(548,'Command: modify energy'),(549,'Command: modify faction'),(550,'Command: modify gender'),(551,'Command: modify honor'),(552,'Command: modify hp'),(553,'Command: modify mana'),(554,'Command: modify money'),(555,'Command: modify mount'),(556,'Command: modify phase'),(557,'Command: modify rage'),(558,'Command: modify reputation'),(559,'Command: modify runicpower'),(560,'Command: modify scale'),(561,'Command: modify speed'),(562,'Command: modify speed all'),(563,'Command: modify speed backwalk'),(564,'Command: modify speed fly'),(565,'Command: modify speed walk'),(566,'Command: modify speed swim'),(567,'Command: modify spell'),(568,'Command: modify standstate'),(569,'Command: modify talentpoints'),(570,'Command: npc'),(571,'Command: npc add'),(572,'Command: npc add formation'),(573,'Command: npc add item'),(574,'Command: npc add move'),(575,'Command: npc add temp'),(576,'Command: npc add delete'),(577,'Command: npc add delete item'),(578,'Command: npc add follow'),(579,'Command: npc add follow stop'),(580,'Command: npc set'),(581,'Command: npc set allowmove'),(582,'Command: npc set entry'),(583,'Command: npc set factionid'),(584,'Command: npc set flag'),(585,'Command: npc set level'),(586,'Command: npc set link'),(587,'Command: npc set model'),(588,'Command: npc set movetype'),(589,'Command: npc set phase'),(590,'Command: npc set spawndist'),(591,'Command: npc set spawntime'),(592,'Command: npc set data'),(593,'Command: npc info'),(594,'Command: npc near'),(595,'Command: npc move'),(596,'Command: npc playemote'),(597,'Command: npc say'),(598,'Command: npc textemote'),(599,'Command: npc whisper'),(600,'Command: npc yell'),(601,'Command: npc tame'),(602,'Command: quest'),(603,'Command: quest add'),(604,'Command: quest complete'),(605,'Command: quest remove'),(606,'Command: quest reward'),(607,'Command: reload'),(608,'Command: reload access_requirement'),(609,'Command: reload achievement_criteria_data'),(610,'Command: reload achievement_reward'),(611,'Command: reload all'),(612,'Command: reload all achievement'),(613,'Command: reload all area'),(615,'Command: reload all gossips'),(616,'Command: reload all item'),(617,'Command: reload all locales'),(618,'Command: reload all loot'),(619,'Command: reload all npc'),(620,'Command: reload all quest'),(621,'Command: reload all scripts'),(622,'Command: reload all spell'),(623,'Command: reload areatrigger_involvedrelation'),(624,'Command: reload areatrigger_tavern'),(625,'Command: reload areatrigger_teleport'),(626,'Command: reload auctions'),(627,'Command: reload autobroadcast'),(628,'Command: reload command'),(629,'Command: reload conditions'),(630,'Command: reload config'),(631,'Command: reload battleground_template'),(632,'Command: .mutehistory'),(633,'Command: reload creature_linked_respawn'),(634,'Command: reload creature_loot_template'),(635,'Command: reload creature_onkill_reputation'),(636,'Command: reload creature_questender'),(637,'Command: reload creature_queststarter'),(638,'Command: reload creature_summon_groups'),(639,'Command: reload creature_template'),(640,'Command: reload creature_text'),(641,'Command: reload disables'),(642,'Command: reload disenchant_loot_template'),(643,'Command: reload event_scripts'),(644,'Command: reload fishing_loot_template'),(645,'Command: reload game_graveyard_zone'),(646,'Command: reload game_tele'),(647,'Command: reload gameobject_questender'),(648,'Command: reload gameobject_loot_template'),(649,'Command: reload gameobject_queststarter'),(650,'Command: reload gm_tickets'),(651,'Command: reload gossip_menu'),(652,'Command: reload gossip_menu_option'),(653,'Command: reload item_enchantment_template'),(654,'Command: reload item_loot_template'),(655,'Command: reload item_set_names'),(656,'Command: reload lfg_dungeon_rewards'),(657,'Command: reload locales_achievement_reward'),(658,'Command: reload locales_creature'),(659,'Command: reload locales_creature_text'),(660,'Command: reload locales_gameobject'),(661,'Command: reload locales_gossip_menu_option'),(662,'Command: reload locales_item'),(663,'Command: reload locales_item_set_name'),(664,'Command: reload locales_npc_text'),(665,'Command: reload locales_page_text'),(666,'Command: reload locales_points_of_interest'),(667,'Command: reload locales_quest'),(668,'Command: reload mail_level_reward'),(669,'Command: reload mail_loot_template'),(670,'Command: reload milling_loot_template'),(671,'Command: reload npc_spellclick_spells'),(672,'Command: reload npc_trainer'),(673,'Command: reload npc_vendor'),(674,'Command: reload page_text'),(675,'Command: reload pickpocketing_loot_template'),(676,'Command: reload points_of_interest'),(677,'Command: reload prospecting_loot_template'),(678,'Command: reload quest_poi'),(679,'Command: reload quest_template'),(680,'Command: reload rbac'),(681,'Command: reload reference_loot_template'),(682,'Command: reload reserved_name'),(683,'Command: reload reputation_reward_rate'),(684,'Command: reload reputation_spillover_template'),(685,'Command: reload skill_discovery_template'),(686,'Command: reload skill_extra_item_template'),(687,'Command: reload skill_fishing_base_level'),(688,'Command: reload skinning_loot_template'),(689,'Command: reload smart_scripts'),(690,'Command: reload spell_required'),(691,'Command: reload spell_area'),(693,'Command: reload spell_group'),(694,'Command: reload spell_learn_spell'),(695,'Command: reload spell_loot_template'),(696,'Command: reload spell_linked_spell'),(697,'Command: reload spell_pet_auras'),(698,'Command: reload spell_proc_event'),(699,'Command: reload spell_proc'),(700,'Command: reload spell_scripts'),(701,'Command: reload spell_target_position'),(702,'Command: reload spell_threats'),(703,'Command: reload spell_group_stack_rules'),(704,'Command: reload trinity_string'),(705,'Command: reload warden_action'),(706,'Command: reload waypoint_scripts'),(707,'Command: reload waypoint_data'),(708,'Command: reload vehicle_accessory'),(709,'Command: reload vehicle_template_accessory'),(710,'Command: reset'),(711,'Command: reset achievements'),(712,'Command: reset honor'),(713,'Command: reset level'),(714,'Command: reset spells'),(715,'Command: reset stats'),(716,'Command: reset talents'),(717,'Command: reset all'),(718,'Command: server'),(719,'Command: server corpses'),(720,'Command: server exit'),(721,'Command: server idlerestart'),(722,'Command: server idlerestart cancel'),(723,'Command: server idleshutdown'),(724,'Command: server idleshutdown cancel'),(725,'Command: server info'),(726,'Command: server plimit'),(727,'Command: server restart'),(728,'Command: server restart cancel'),(729,'Command: server set'),(730,'Command: server set closed'),(731,'Command: server set difftime'),(732,'Command: server set loglevel'),(733,'Command: server set motd'),(734,'Command: server shutdown'),(735,'Command: server shutdown cancel'),(736,'Command: server motd'),(737,'Command: tele'),(738,'Command: tele add'),(739,'Command: tele del'),(740,'Command: tele name'),(741,'Command: tele group'),(742,'Command: ticket'),(743,'Command: ticket assign'),(744,'Command: ticket close'),(745,'Command: ticket closedlist'),(746,'Command: ticket comment'),(747,'Command: ticket complete'),(748,'Command: ticket delete'),(749,'Command: ticket escalate'),(750,'Command: ticket escalatedlist'),(751,'Command: ticket list'),(752,'Command: ticket onlinelist'),(753,'Command: ticket reset'),(754,'Command: ticket response'),(755,'Command: ticket response append'),(756,'Command: ticket response appendln'),(757,'Command: ticket togglesystem'),(758,'Command: ticket unassign'),(759,'Command: ticket viewid'),(760,'Command: ticket viewname'),(761,'Command: titles'),(762,'Command: titles add'),(763,'Command: titles current'),(764,'Command: titles remove'),(765,'Command: titles set'),(766,'Command: titles set mask'),(767,'Command: wp'),(768,'Command: wp add'),(769,'Command: wp event'),(770,'Command: wp load'),(771,'Command: wp modify'),(772,'Command: wp unload'),(773,'Command: wp reload'),(774,'Command: wp show'),(777,'Command: mailbox'),(778,'Command: ahbot'),(779,'Command: ahbot items'),(780,'Command: ahbot items gray'),(781,'Command: ahbot items white'),(782,'Command: ahbot items green'),(783,'Command: ahbot items blue'),(784,'Command: ahbot items purple'),(785,'Command: ahbot items orange'),(786,'Command: ahbot items yellow'),(787,'Command: ahbot ratio'),(788,'Command: ahbot ratio alliance'),(789,'Command: ahbot ratio horde'),(790,'Command: ahbot ratio neutral'),(791,'Command: ahbot rebuild'),(792,'Command: ahbot reload'),(793,'Command: ahbot status'),(794,'Command: .guild info'),(797,'Command: pvpstats'),(798,'Command: .mod xp'); +INSERT INTO `rbac_permissions` VALUES (1,'Instant logout'),(2,'Skip Queue'),(3,'Join Normal Battleground'),(4,'Join Random Battleground'),(5,'Join Arenas'),(6,'Join Dungeon Finder'),(11,'Log GM trades'),(13,'Skip Instance required bosses check'),(14,'Skip character creation team mask check'),(15,'Skip character creation class mask check'),(16,'Skip character creation race mask check'),(17,'Skip character creation reserved name check'),(18,'Skip character creation heroic min level check'),(19,'Skip needed requirements to use channel check'),(20,'Skip disable map check'),(21,'Skip reset talents when used more than allowed check'),(22,'Skip spam chat check'),(23,'Skip over-speed ping check'),(24,'Two side faction characters on the same account'),(25,'Allow say chat between factions'),(26,'Allow channel chat between factions'),(27,'Two side mail interaction'),(28,'See two side who list'),(29,'Add friends of other faction'),(30,'Save character without delay with .save command'),(31,'Use params with .unstuck command'),(32,'Can be assigned tickets with .assign ticket command'),(33,'Notify if a command was not found'),(34,'Check if should appear in list using .gm ingame command'),(35,'See all security levels with who command'),(36,'Filter whispers'),(37,'Use staff badge in chat'),(38,'Resurrect with full Health Points'),(39,'Restore saved gm setting states'),(40,'Allows to add a gm to friend list'),(41,'Use Config option START_GM_LEVEL to assign new character level'),(42,'Allows to use CMSG_WORLD_TELEPORT opcode'),(43,'Allows to use CMSG_WHOIS opcode'),(44,'Receive global GM messages/texts'),(45,'Join channels without announce'),(46,'Change channel settings without being channel moderator'),(47,'Enables lower security than target check'),(48,'Enable IP, Last Login and EMail output in pinfo'),(49,'Forces to enter the email for confirmation on password change'),(50,'Allow user to check his own email with .account'),(51,'Allow trading between factions'),(192,'Role: Sec Level Administrator'),(193,'Role: Sec Level Gamemaster'),(194,'Role: Sec Level Moderator'),(195,'Role: Sec Level Player'),(196,'Role: Administrator Commands'),(197,'Role: Gamemaster Commands'),(198,'Role: Moderator Commands'),(199,'Role: Player Commands'),(200,'Command: rbac'),(201,'Command: rbac account'),(202,'Command: rbac account list'),(203,'Command: rbac account grant'),(204,'Command: rbac account deny'),(205,'Command: rbac account revoke'),(206,'Command: rbac list'),(207,'Command: battlenetaccount'),(208,'Command: battlenetaccount create'),(209,'Command: battlenetaccount lock country'),(210,'Command: battlenetaccount lock ip'),(211,'Command: battlenetaccount password'),(212,'Command: battlenetaccount set'),(213,'Command: battlenetaccount set password'),(214,'Command: bnetaccount link'),(215,'Command: bnetaccount unlink'),(216,'Command: bnetaccount gameaccountcreate'),(217,'Command: account'),(218,'Command: account addon'),(219,'Command: account create'),(220,'Command: account delete'),(221,'Command: account lock'),(222,'Command: account lock country'),(223,'Command: account lock ip'),(224,'Command: account onlinelist'),(225,'Command: account password'),(226,'Command: account set'),(227,'Command: account set addon'),(228,'Command: account set gmlevel'),(229,'Command: account set password'),(230,'Command: achievement'),(231,'Command: achievement add'),(232,'Command: arena'),(233,'Command: arena captain'),(234,'Command: arena create'),(235,'Command: arena disband'),(236,'Command: arena info'),(237,'Command: arena lookup'),(238,'Command: arena rename'),(239,'Command: ban'),(240,'Command: ban account'),(241,'Command: ban character'),(242,'Command: ban ip'),(243,'Command: ban playeraccount'),(244,'Command: baninfo'),(245,'Command: baninfo account'),(246,'Command: baninfo character'),(247,'Command: baninfo ip'),(248,'Command: banlist'),(249,'Command: banlist account'),(250,'Command: banlist character'),(251,'Command: banlist ip'),(252,'Command: unban'),(253,'Command: unban account'),(254,'Command: unban character'),(255,'Command: unban ip'),(256,'Command: unban playeraccount'),(257,'Command: bf'),(258,'Command: bf start'),(259,'Command: bf stop'),(260,'Command: bf switch'),(261,'Command: bf timer'),(262,'Command: bf enable'),(263,'Command: account email'),(264,'Command: account set sec'),(265,'Command: account set sec email'),(266,'Command: account set sec regmail'),(267,'Command: cast'),(268,'Command: cast back'),(269,'Command: cast dist'),(270,'Command: cast self'),(271,'Command: cast target'),(272,'Command: cast dest'),(273,'Command: character'),(274,'Command: character customize'),(275,'Command: character changefaction'),(276,'Command: character changerace'),(277,'Command: character deleted'),(279,'Command: character deleted list'),(280,'Command: character deleted restore'),(283,'Command: character level'),(284,'Command: character rename'),(285,'Command: character reputation'),(286,'Command: character titles'),(287,'Command: levelup'),(288,'Command: pdump'),(289,'Command: pdump load'),(290,'Command: pdump write'),(291,'Command: cheat'),(292,'Command: cheat casttime'),(293,'Command: cheat cooldown'),(294,'Command: cheat explore'),(295,'Command: cheat god'),(296,'Command: cheat power'),(297,'Command: cheat status'),(298,'Command: cheat taxi'),(299,'Command: cheat waterwalk'),(300,'Command: debug'),(301,'Command: debug anim'),(302,'Command: debug areatriggers'),(303,'Command: debug arena'),(304,'Command: debug bg'),(305,'Command: debug entervehicle'),(306,'Command: debug getitemstate'),(307,'Command: debug getitemvalue'),(308,'Command: debug getvalue'),(309,'Command: debug hostil'),(310,'Command: debug itemexpire'),(311,'Command: debug lootrecipient'),(312,'Command: debug los'),(313,'Command: debug mod32value'),(314,'Command: debug moveflags'),(315,'Command: debug play'),(316,'Command: debug play cinematics'),(317,'Command: debug play movie'),(318,'Command: debug play sound'),(319,'Command: debug send'),(320,'Command: debug send buyerror'),(321,'Command: debug send channelnotify'),(322,'Command: debug send chatmessage'),(323,'Command: debug send equiperror'),(324,'Command: debug send largepacket'),(325,'Command: debug send opcode'),(326,'Command: debug send qinvalidmsg'),(327,'Command: debug send qpartymsg'),(328,'Command: debug send sellerror'),(329,'Command: debug send setphaseshift'),(330,'Command: debug send spellfail'),(331,'Command: debug setaurastate'),(332,'Command: debug setbit'),(333,'Command: debug setitemvalue'),(334,'Command: debug setvalue'),(335,'Command: debug setvid'),(336,'Command: debug spawnvehicle'),(337,'Command: debug threat'),(338,'Command: debug update'),(339,'Command: debug uws'),(340,'Command: wpgps'),(341,'Command: deserter'),(342,'Command: deserter bg'),(343,'Command: deserter bg add'),(344,'Command: deserter bg remove'),(345,'Command: deserter instance'),(346,'Command: deserter instance add'),(347,'Command: deserter instance remove'),(348,'Command: disable'),(349,'Command: disable add'),(350,'Command: disable add achievement_criteria'),(351,'Command: disable add battleground'),(352,'Command: disable add map'),(353,'Command: disable add mmap'),(354,'Command: disable add outdoorpvp'),(355,'Command: disable add quest'),(356,'Command: disable add spell'),(357,'Command: disable add vmap'),(358,'Command: disable remove'),(359,'Command: disable remove achievement_criteria'),(360,'Command: disable remove battleground'),(361,'Command: disable remove map'),(362,'Command: disable remove mmap'),(363,'Command: disable remove outdoorpvp'),(364,'Command: disable remove quest'),(365,'Command: disable remove spell'),(366,'Command: disable remove vmap'),(367,'Command: event'),(368,'Command: event activelist'),(369,'Command: event start'),(370,'Command: event stop'),(371,'Command: gm'),(372,'Command: gm chat'),(373,'Command: gm fly'),(374,'Command: gm ingame'),(375,'Command: gm list'),(376,'Command: gm visible'),(377,'Command: go'),(378,'Command: go creature'),(379,'Command: go graveyard'),(380,'Command: go grid'),(381,'Command: go object'),(382,'Command: go taxinode'),(383,'Command: go ticket'),(384,'Command: go trigger'),(385,'Command: go xyz'),(386,'Command: go zonexy'),(387,'Command: gobject'),(388,'Command: gobject activate'),(389,'Command: gobject add'),(390,'Command: gobject add temp'),(391,'Command: gobject delete'),(392,'Command: gobject info'),(393,'Command: gobject move'),(394,'Command: gobject near'),(395,'Command: gobject set'),(396,'Command: gobject set phase'),(397,'Command: gobject set state'),(398,'Command: gobject target'),(399,'Command: gobject turn'),(400,'debug transport'),(401,'Command: guild'),(402,'Command: guild create'),(403,'Command: guild delete'),(404,'Command: guild invite'),(405,'Command: guild uninvite'),(406,'Command: guild rank'),(407,'Command: guild rename'),(408,'Command: honor'),(409,'Command: honor add'),(410,'Command: honor add kill'),(411,'Command: honor update'),(412,'Command: instance'),(413,'Command: instance listbinds'),(414,'Command: instance unbind'),(415,'Command: instance stats'),(416,'Command: instance savedata'),(417,'Command: learn'),(418,'Command: learn all'),(419,'Command: learn all my'),(420,'Command: learn all my class'),(421,'Command: learn all my pettalents'),(422,'Command: learn all my spells'),(423,'Command: learn all my talents'),(424,'Command: learn all gm'),(425,'Command: learn all crafts'),(426,'Command: learn all default'),(427,'Command: learn all lang'),(428,'Command: learn all recipes'),(429,'Command: unlearn'),(430,'Command: lfg'),(431,'Command: lfg player'),(432,'Command: lfg group'),(433,'Command: lfg queue'),(434,'Command: lfg clean'),(435,'Command: lfg options'),(436,'Command: list'),(437,'Command: list creature'),(438,'Command: list item'),(439,'Command: list object'),(440,'Command: list auras'),(441,'Command: list mail'),(442,'Command: lookup'),(443,'Command: lookup area'),(444,'Command: lookup creature'),(445,'Command: lookup event'),(446,'Command: lookup faction'),(447,'Command: lookup item'),(448,'Command: lookup itemset'),(449,'Command: lookup object'),(450,'Command: lookup quest'),(451,'Command: lookup player'),(452,'Command: lookup player ip'),(453,'Command: lookup player account'),(454,'Command: lookup player email'),(455,'Command: lookup skill'),(456,'Command: lookup spell'),(457,'Command: lookup spell id'),(458,'Command: lookup taxinode'),(459,'Command: lookup tele'),(460,'Command: lookup title'),(461,'Command: lookup map'),(462,'Command: announce'),(463,'Command: channel'),(464,'Command: channel set'),(465,'Command: channel set ownership'),(466,'Command: gmannounce'),(467,'Command: gmnameannounce'),(468,'Command: gmnotify'),(469,'Command: nameannounce'),(470,'Command: notify'),(471,'Command: whispers'),(472,'Command: group'),(473,'Command: group leader'),(474,'Command: group disband'),(475,'Command: group remove'),(476,'Command: group join'),(477,'Command: group list'),(478,'Command: group summon'),(479,'Command: pet'),(480,'Command: pet create'),(481,'Command: pet learn'),(482,'Command: pet unlearn'),(483,'Command: send'),(484,'Command: send items'),(485,'Command: send mail'),(486,'Command: send message'),(487,'Command: send money'),(488,'Command: additem'),(489,'Command: additemset'),(490,'Command: appear'),(491,'Command: aura'),(492,'Command: bank'),(493,'Command: bindsight'),(494,'Command: combatstop'),(495,'Command: cometome'),(496,'Command: commands'),(497,'Command: cooldown'),(498,'Command: damage'),(499,'Command: dev'),(500,'Command: die'),(501,'Command: dismount'),(502,'Command: distance'),(503,'Command: flusharenapoints'),(504,'Command: freeze'),(505,'Command: gps'),(506,'Command: guid'),(507,'Command: help'),(508,'Command: hidearea'),(509,'Command: itemmove'),(510,'Command: kick'),(511,'Command: linkgrave'),(512,'Command: listfreeze'),(513,'Command: maxskill'),(514,'Command: movegens'),(515,'Command: mute'),(516,'Command: neargrave'),(517,'Command: pinfo'),(518,'Command: playall'),(519,'Command: possess'),(520,'Command: recall'),(521,'Command: repairitems'),(522,'Command: respawn'),(523,'Command: revive'),(524,'Command: saveall'),(525,'Command: save'),(526,'Command: setskill'),(527,'Command: showarea'),(528,'Command: summon'),(529,'Command: unaura'),(530,'Command: unbindsight'),(531,'Command: unfreeze'),(532,'Command: unmute'),(533,'Command: unpossess'),(534,'Command: unstuck'),(535,'Command: wchange'),(536,'Command: mmap'),(537,'Command: mmap loadedtiles'),(538,'Command: mmap loc'),(539,'Command: mmap path'),(540,'Command: mmap stats'),(541,'Command: mmap testarea'),(542,'Command: morph'),(543,'Command: demorph'),(544,'Command: modify'),(545,'Command: modify arenapoints'),(546,'Command: modify bit'),(547,'Command: modify drunk'),(548,'Command: modify energy'),(549,'Command: modify faction'),(550,'Command: modify gender'),(551,'Command: modify honor'),(552,'Command: modify hp'),(553,'Command: modify mana'),(554,'Command: modify money'),(555,'Command: modify mount'),(556,'Command: modify phase'),(557,'Command: modify rage'),(558,'Command: modify reputation'),(559,'Command: modify runicpower'),(560,'Command: modify scale'),(561,'Command: modify speed'),(562,'Command: modify speed all'),(563,'Command: modify speed backwalk'),(564,'Command: modify speed fly'),(565,'Command: modify speed walk'),(566,'Command: modify speed swim'),(567,'Command: modify spell'),(568,'Command: modify standstate'),(569,'Command: modify talentpoints'),(570,'Command: npc'),(571,'Command: npc add'),(572,'Command: npc add formation'),(573,'Command: npc add item'),(574,'Command: npc add move'),(575,'Command: npc add temp'),(576,'Command: npc add delete'),(577,'Command: npc add delete item'),(578,'Command: npc add follow'),(579,'Command: npc add follow stop'),(580,'Command: npc set'),(581,'Command: npc set allowmove'),(582,'Command: npc set entry'),(583,'Command: npc set factionid'),(584,'Command: npc set flag'),(585,'Command: npc set level'),(586,'Command: npc set link'),(587,'Command: npc set model'),(588,'Command: npc set movetype'),(589,'Command: npc set phase'),(590,'Command: npc set spawndist'),(591,'Command: npc set spawntime'),(592,'Command: npc set data'),(593,'Command: npc info'),(594,'Command: npc near'),(595,'Command: npc move'),(596,'Command: npc playemote'),(597,'Command: npc say'),(598,'Command: npc textemote'),(599,'Command: npc whisper'),(600,'Command: npc yell'),(601,'Command: npc tame'),(602,'Command: quest'),(603,'Command: quest add'),(604,'Command: quest complete'),(605,'Command: quest remove'),(606,'Command: quest reward'),(607,'Command: reload'),(608,'Command: reload access_requirement'),(609,'Command: reload achievement_criteria_data'),(610,'Command: reload achievement_reward'),(611,'Command: reload all'),(612,'Command: reload all achievement'),(613,'Command: reload all area'),(615,'Command: reload all gossips'),(616,'Command: reload all item'),(617,'Command: reload all locales'),(618,'Command: reload all loot'),(619,'Command: reload all npc'),(620,'Command: reload all quest'),(621,'Command: reload all scripts'),(622,'Command: reload all spell'),(623,'Command: reload areatrigger_involvedrelation'),(624,'Command: reload areatrigger_tavern'),(625,'Command: reload areatrigger_teleport'),(626,'Command: reload auctions'),(627,'Command: reload autobroadcast'),(628,'Command: reload command'),(629,'Command: reload conditions'),(630,'Command: reload config'),(631,'Command: reload battleground_template'),(632,'Command: .mutehistory'),(633,'Command: reload creature_linked_respawn'),(634,'Command: reload creature_loot_template'),(635,'Command: reload creature_onkill_reputation'),(636,'Command: reload creature_questender'),(637,'Command: reload creature_queststarter'),(638,'Command: reload creature_summon_groups'),(639,'Command: reload creature_template'),(640,'Command: reload creature_text'),(641,'Command: reload disables'),(642,'Command: reload disenchant_loot_template'),(643,'Command: reload event_scripts'),(644,'Command: reload fishing_loot_template'),(645,'Command: reload game_graveyard_zone'),(646,'Command: reload game_tele'),(647,'Command: reload gameobject_questender'),(648,'Command: reload gameobject_loot_template'),(649,'Command: reload gameobject_queststarter'),(650,'Command: reload gm_tickets'),(651,'Command: reload gossip_menu'),(652,'Command: reload gossip_menu_option'),(653,'Command: reload item_enchantment_template'),(654,'Command: reload item_loot_template'),(655,'Command: reload item_set_names'),(656,'Command: reload lfg_dungeon_rewards'),(657,'Command: reload locales_achievement_reward'),(658,'Command: reload locales_creature'),(659,'Command: reload locales_creature_text'),(660,'Command: reload locales_gameobject'),(661,'Command: reload locales_gossip_menu_option'),(662,'Command: reload locales_item'),(663,'Command: reload locales_item_set_name'),(664,'Command: reload locales_npc_text'),(665,'Command: reload locales_page_text'),(666,'Command: reload locales_points_of_interest'),(667,'Command: reload locales_quest'),(668,'Command: reload mail_level_reward'),(669,'Command: reload mail_loot_template'),(670,'Command: reload milling_loot_template'),(671,'Command: reload npc_spellclick_spells'),(672,'Command: reload npc_trainer'),(673,'Command: reload npc_vendor'),(674,'Command: reload page_text'),(675,'Command: reload pickpocketing_loot_template'),(676,'Command: reload points_of_interest'),(677,'Command: reload prospecting_loot_template'),(678,'Command: reload quest_poi'),(679,'Command: reload quest_template'),(680,'Command: reload rbac'),(681,'Command: reload reference_loot_template'),(682,'Command: reload reserved_name'),(683,'Command: reload reputation_reward_rate'),(684,'Command: reload reputation_spillover_template'),(685,'Command: reload skill_discovery_template'),(686,'Command: reload skill_extra_item_template'),(687,'Command: reload skill_fishing_base_level'),(688,'Command: reload skinning_loot_template'),(689,'Command: reload smart_scripts'),(690,'Command: reload spell_required'),(691,'Command: reload spell_area'),(693,'Command: reload spell_group'),(694,'Command: reload spell_learn_spell'),(695,'Command: reload spell_loot_template'),(696,'Command: reload spell_linked_spell'),(697,'Command: reload spell_pet_auras'),(698,'Command: reload spell_proc_event'),(699,'Command: reload spell_proc'),(700,'Command: reload spell_scripts'),(701,'Command: reload spell_target_position'),(702,'Command: reload spell_threats'),(703,'Command: reload spell_group_stack_rules'),(704,'Command: reload trinity_string'),(705,'Command: reload warden_action'),(706,'Command: reload waypoint_scripts'),(707,'Command: reload waypoint_data'),(708,'Command: reload vehicle_accessory'),(709,'Command: reload vehicle_template_accessory'),(710,'Command: reset'),(711,'Command: reset achievements'),(712,'Command: reset honor'),(713,'Command: reset level'),(714,'Command: reset spells'),(715,'Command: reset stats'),(716,'Command: reset talents'),(717,'Command: reset all'),(718,'Command: server'),(719,'Command: server corpses'),(720,'Command: server exit'),(721,'Command: server idlerestart'),(722,'Command: server idlerestart cancel'),(723,'Command: server idleshutdown'),(724,'Command: server idleshutdown cancel'),(725,'Command: server info'),(726,'Command: server plimit'),(727,'Command: server restart'),(728,'Command: server restart cancel'),(729,'Command: server set'),(730,'Command: server set closed'),(731,'Command: server set difftime'),(732,'Command: server set loglevel'),(733,'Command: server set motd'),(734,'Command: server shutdown'),(735,'Command: server shutdown cancel'),(736,'Command: server motd'),(737,'Command: tele'),(738,'Command: tele add'),(739,'Command: tele del'),(740,'Command: tele name'),(741,'Command: tele group'),(742,'Command: ticket'),(743,'Command: ticket assign'),(744,'Command: ticket close'),(745,'Command: ticket closedlist'),(746,'Command: ticket comment'),(747,'Command: ticket complete'),(748,'Command: ticket delete'),(749,'Command: ticket escalate'),(750,'Command: ticket escalatedlist'),(751,'Command: ticket list'),(752,'Command: ticket onlinelist'),(753,'Command: ticket reset'),(754,'Command: ticket response'),(755,'Command: ticket response append'),(756,'Command: ticket response appendln'),(757,'Command: ticket togglesystem'),(758,'Command: ticket unassign'),(759,'Command: ticket viewid'),(760,'Command: ticket viewname'),(761,'Command: titles'),(762,'Command: titles add'),(763,'Command: titles current'),(764,'Command: titles remove'),(765,'Command: titles set'),(766,'Command: titles set mask'),(767,'Command: wp'),(768,'Command: wp add'),(769,'Command: wp event'),(770,'Command: wp load'),(771,'Command: wp modify'),(772,'Command: wp unload'),(773,'Command: wp reload'),(774,'Command: wp show'),(777,'Command: mailbox'),(778,'Command: ahbot'),(779,'Command: ahbot items'),(780,'Command: ahbot items gray'),(781,'Command: ahbot items white'),(782,'Command: ahbot items green'),(783,'Command: ahbot items blue'),(784,'Command: ahbot items purple'),(785,'Command: ahbot items orange'),(786,'Command: ahbot items yellow'),(787,'Command: ahbot ratio'),(788,'Command: ahbot ratio alliance'),(789,'Command: ahbot ratio horde'),(790,'Command: ahbot ratio neutral'),(791,'Command: ahbot rebuild'),(792,'Command: ahbot reload'),(793,'Command: ahbot status'),(794,'Command: .guild info'),(797,'Command: pvpstats'),(798,'Command: .mod xp'); /*!40000 ALTER TABLE `rbac_permissions` ENABLE KEYS */; UNLOCK TABLES; @@ -621,4 +621,4 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2014-12-20 11:26:27 +-- Dump completed on 2014-12-27 18:09:09 diff --git a/sql/updates/auth/2014_12_27_00_auth.sql b/sql/updates/auth/2014_12_27_00_auth.sql new file mode 100644 index 00000000000..ddea3d335ff --- /dev/null +++ b/sql/updates/auth/2014_12_27_00_auth.sql @@ -0,0 +1,9 @@ +-- Add rbac_permissions +DELETE FROM `rbac_permissions` WHERE `id` = 51; +INSERT INTO `rbac_permissions` (`id`,`name`) VALUES +(51, 'Allow trading between factions'); + +-- Add rbac_linked_permissions +DELETE FROM `rbac_linked_permissions` WHERE `linkedId` = 51; +INSERT INTO `rbac_linked_permissions` (`id`,`linkedId`) VALUES +(194, 51); diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index bb347113e60..54dcb73fb35 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -100,6 +100,7 @@ enum RBACPermissions RBAC_PERM_COMMANDS_PINFO_CHECK_PERSONAL_DATA = 48, RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE = 49, RBAC_PERM_MAY_CHECK_OWN_EMAIL = 50, + RBAC_PERM_ALLOW_TWO_SIDE_TRADE = 51, // Free space for core permissions (till 149) // Roles (Permissions with delegated permissions) use 199 and descending diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index dd5563e7a52..aa4579508f2 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -773,7 +773,9 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) return; } - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam()) + if (pOther->GetTeam() != _player->GetTeam() && + (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && + !GetPlayer()->GetSession()->HasPermission(rbac::RBAC_PERM_ALLOW_TWO_SIDE_TRADE))) { info.Status = TRADE_STATUS_WRONG_FACTION; SendTradeStatus(info); -- cgit v1.2.3 From ccf2b36c0c704361145a8f7bfc21e4ca50172248 Mon Sep 17 00:00:00 2001 From: Aokromes Date: Sun, 28 Dec 2014 10:20:23 +0100 Subject: Core/Logs: Move runtime log to debug because it's already checked at startup. --- src/server/game/AI/SmartScripts/SmartScript.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 6f14b3a04a8..88b5133baac 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -2276,7 +2276,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (linked) ProcessEvent(linked, unit, var0, var1, bvar, spell, gob); else - TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry " SI64FMTD " SourceType %u, Event %u, Link Event %u not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link); + TC_LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: Entry " SI64FMTD " SourceType %u, Event %u, Link Event %u not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link); } } @@ -3248,7 +3248,7 @@ void SmartScript::InitTimer(SmartScriptHolder& e) break; } } -void SmartScript::RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max) +vbegin(); itr != units-oid SmartScript::RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max) { // min/max was checked at loading! e.timer = urand(min, max); -- cgit v1.2.3 From 257f46e678ba1c28a967cad7ce226c402d00b27c Mon Sep 17 00:00:00 2001 From: Rat Date: Sun, 28 Dec 2014 10:34:33 +0100 Subject: Core/Aokromes: typo? fix --- src/server/game/AI/SmartScripts/SmartScript.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 88b5133baac..2e86a78148a 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3248,7 +3248,7 @@ void SmartScript::InitTimer(SmartScriptHolder& e) break; } } -vbegin(); itr != units-oid SmartScript::RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max) +void SmartScript::RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max) { // min/max was checked at loading! e.timer = urand(min, max); -- cgit v1.2.3 From be0009d01aaab6630f53a698277c14e50d08c99a Mon Sep 17 00:00:00 2001 From: MitchesD Date: Sun, 28 Dec 2014 12:08:07 +0100 Subject: Scripts/ICC: fixed situations when LK tried to cast Necrotic Plague on pets and then Necrotic Plague was omitted (cherry picked from commit 3d3dafbe380054ef60cbf99658aa42c442b01693) --- src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 645df91d8ea..1b6df68c5c4 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -362,7 +362,7 @@ class NecroticPlagueTargetCheck : public std::unary_function bool operator()(Unit* unit) const { - if (!unit || unit == _sourceObj || !unit->isTargetableForAttack() || unit->IsTotem() || unit->HasAura(SPELL_PLAGUE_AVOIDANCE)) + if (!unit || unit == _sourceObj || !unit->isTargetableForAttack() || unit->GetTypeId() != TYPEID_PLAYER || unit->HasAura(SPELL_PLAGUE_AVOIDANCE)) return false; if ((_notAura1 && unit->HasAura(_notAura1)) || (_notAura2 && unit->HasAura(_notAura2))) return false; -- cgit v1.2.3 From 12ef5ad90a2bbe367651f82224d785c97b786930 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 28 Dec 2014 15:02:20 +0100 Subject: Core/Battle.net: Fixed another client crash happening when logging out to character list --- src/server/bnetserver/Realms/WorldListener.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/server/bnetserver/Realms/WorldListener.cpp b/src/server/bnetserver/Realms/WorldListener.cpp index d84425496c7..8a6133c44e6 100644 --- a/src/server/bnetserver/Realms/WorldListener.cpp +++ b/src/server/bnetserver/Realms/WorldListener.cpp @@ -110,6 +110,9 @@ void WorldListener::HandleToonOnlineStatusChange(Battlenet::RealmHandle const& r } } else if (session->IsToonOnline()) + { session->AsyncWrite(new Battlenet::WoWRealm::ToonLoggedOut()); + session->SetToonOnline(false); + } } } -- cgit v1.2.3 From 483b6ad5a8a36c85cb657b3ed6d0c31b241eeb87 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 28 Dec 2014 16:21:35 +0100 Subject: Core/Achievements: Updated achievements - progress is currently not saved until a conversion of existing data from old to new criteria is made --- sql/updates/world/2014_12_28_00_world.sql | 2 + src/server/game/Achievements/AchievementMgr.cpp | 1329 ++++++++++---------- src/server/game/Achievements/AchievementMgr.h | 133 +- src/server/game/DataStores/DBCEnums.h | 18 +- src/server/game/DataStores/DBCStores.cpp | 25 +- src/server/game/DataStores/DBCStores.h | 4 +- src/server/game/DataStores/DBCStructure.h | 608 ++------- src/server/game/DataStores/DBCfmt.h | 8 +- src/server/game/Guilds/Guild.cpp | 6 +- src/server/game/Guilds/Guild.h | 2 +- .../game/Server/Packets/AchievementPackets.cpp | 74 ++ .../game/Server/Packets/AchievementPackets.h | 93 ++ src/server/game/Server/Protocol/Opcodes.cpp | 6 +- src/server/game/Server/Protocol/Opcodes.h | 12 +- src/server/game/World/World.cpp | 2 + 15 files changed, 1125 insertions(+), 1197 deletions(-) create mode 100644 sql/updates/world/2014_12_28_00_world.sql create mode 100644 src/server/game/Server/Packets/AchievementPackets.cpp create mode 100644 src/server/game/Server/Packets/AchievementPackets.h (limited to 'src') diff --git a/sql/updates/world/2014_12_28_00_world.sql b/sql/updates/world/2014_12_28_00_world.sql new file mode 100644 index 00000000000..e71ec1cf8bb --- /dev/null +++ b/sql/updates/world/2014_12_28_00_world.sql @@ -0,0 +1,2 @@ +DELETE FROM `achievement_criteria_data`; +DELETE FROM `disables` WHERE `sourceType`=4; diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index fcafd9c6d01..c392f9d445a 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -17,6 +17,7 @@ */ #include "AchievementMgr.h" +#include "AchievementPackets.h" #include "ArenaTeam.h" #include "ArenaTeamMgr.h" #include "Battleground.h" @@ -43,7 +44,7 @@ #include "World.h" #include "WorldPacket.h" -bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) +bool AchievementCriteriaData::IsValid(AchievementCriteria const* criteria) { if (dataType >= MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE) { @@ -51,7 +52,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) return false; } - switch (criteria->type) + switch (criteria->Entry->Type) { case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: @@ -81,7 +82,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) default: if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has data for non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->type); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has data for non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->Entry->Type); return false; } break; @@ -96,7 +97,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!creature.id || !sObjectMgr->GetCreatureTemplate(creature.id)) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) has non-existing creature id in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, creature.id); + criteria->ID, criteria->Entry->Type, dataType, creature.id); return false; } return true; @@ -104,19 +105,19 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!classRace.class_id && !classRace.race_id) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.", - criteria->ID, criteria->type, dataType); + criteria->ID, criteria->Entry->Type, dataType); return false; } if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, classRace.class_id); + criteria->ID, criteria->Entry->Type, dataType, classRace.class_id); return false; } if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", - criteria->ID, criteria->type, dataType, classRace.race_id); + criteria->ID, criteria->Entry->Type, dataType, classRace.race_id); return false; } return true; @@ -124,7 +125,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (health.percent < 1 || health.percent > 100) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) has wrong percent value in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, health.percent); + criteria->ID, criteria->Entry->Type, dataType, health.percent); return false; } return true; @@ -135,20 +136,20 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!spellEntry) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell id in value1 (%u), ignored.", - criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id); + criteria->ID, criteria->Entry->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id); return false; } SpellEffectInfo const* effect = spellEntry->GetEffect(DIFFICULTY_NONE, aura.effect_idx); if (!effect) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell effect index in value2 (%u), ignored.", - criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.effect_idx); + criteria->ID, criteria->Entry->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.effect_idx); return false; } if (!effect->ApplyAuraName) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has non-aura spell effect (ID: %u Effect: %u), ignores.", - criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id, aura.effect_idx); + criteria->ID, criteria->Entry->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id, aura.effect_idx); return false; } return true; @@ -157,7 +158,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (value.compType >= COMP_TYPE_MAX) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE (%u) has wrong ComparisionType in value2 (%u), ignored.", - criteria->ID, criteria->type, dataType, value.compType); + criteria->ID, criteria->Entry->Type, dataType, value.compType); return false; } return true; @@ -165,7 +166,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (level.minlevel > STRONG_MAX_LEVEL) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL (%u) has wrong minlevel in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, level.minlevel); + criteria->ID, criteria->Entry->Type, dataType, level.minlevel); return false; } return true; @@ -173,7 +174,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (gender.gender > GENDER_NONE) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER (%u) has wrong gender in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, gender.gender); + criteria->ID, criteria->Entry->Type, dataType, gender.gender); return false; } return true; @@ -181,7 +182,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!ScriptId) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT (%u) does not have ScriptName set, ignored.", - criteria->ID, criteria->type, dataType); + criteria->ID, criteria->Entry->Type, dataType); return false; } return true; @@ -189,7 +190,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (map_players.maxcount <= 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT (%u) has wrong max players count in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, map_players.maxcount); + criteria->ID, criteria->Entry->Type, dataType, map_players.maxcount); return false; } return true; @@ -197,7 +198,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (team.team != ALLIANCE && team.team != HORDE) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM (%u) has unknown team in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, team.team); + criteria->ID, criteria->Entry->Type, dataType, team.team); return false; } return true; @@ -205,7 +206,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (drunk.state >= MAX_DRUNKEN) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK (%u) has unknown drunken state in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, drunk.state); + criteria->ID, criteria->Entry->Type, dataType, drunk.state); return false; } return true; @@ -213,7 +214,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!sHolidaysStore.LookupEntry(holiday.id)) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY (%u) has unknown holiday in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, holiday.id); + criteria->ID, criteria->Entry->Type, dataType, holiday.id); return false; } return true; @@ -223,7 +224,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (game_event.id < 1 || game_event.id >= events.size()) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT (%u) has unknown game_event in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, game_event.id); + criteria->ID, criteria->Entry->Type, dataType, game_event.id); return false; } return true; @@ -234,7 +235,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (equipped_item.item_quality >= MAX_ITEM_QUALITY) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM (%u) has unknown quality state in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, equipped_item.item_quality); + criteria->ID, criteria->Entry->Type, dataType, equipped_item.item_quality); return false; } return true; @@ -242,19 +243,19 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!classRace.class_id && !classRace.race_id) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.", - criteria->ID, criteria->type, dataType); + criteria->ID, criteria->Entry->Type, dataType); return false; } if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", - criteria->ID, criteria->type, dataType, classRace.class_id); + criteria->ID, criteria->Entry->Type, dataType, classRace.class_id); return false; } if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", - criteria->ID, criteria->type, dataType, classRace.race_id); + criteria->ID, criteria->Entry->Type, dataType, classRace.race_id); return false; } return true; @@ -262,12 +263,12 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!sCharTitlesStore.LookupEntry(known_title.title_id)) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE (%u) have unknown title_id in value1 (%u), ignore.", - criteria->ID, criteria->type, dataType, known_title.title_id); + criteria->ID, criteria->Entry->Type, dataType, known_title.title_id); return false; } return true; default: - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored.", criteria->ID, criteria->type, dataType); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored.", criteria->ID, criteria->Entry->Type, dataType); return false; } } @@ -383,8 +384,8 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target, uint32 miscValue /*= 0*/) const { - for (Storage::const_iterator itr = storage.begin(); itr != storage.end(); ++itr) - if (!itr->Meets(criteria_id, source, target, miscValue)) + for (AchievementCriteriaData const& data : storage) + if (!data.Meets(criteria_id, source, target, miscValue)) return false; return true; @@ -397,22 +398,22 @@ template AchievementMgr::~AchievementMgr() { } template -void AchievementMgr::SendPacket(WorldPacket* data) const { } +void AchievementMgr::SendPacket(WorldPacket const* data) const { } template<> -void AchievementMgr::SendPacket(WorldPacket* data) const +void AchievementMgr::SendPacket(WorldPacket const* data) const { GetOwner()->BroadcastPacket(data); } template<> -void AchievementMgr::SendPacket(WorldPacket* data) const +void AchievementMgr::SendPacket(WorldPacket const* data) const { GetOwner()->GetSession()->SendPacket(data); } template -void AchievementMgr::RemoveCriteriaProgress(AchievementCriteriaEntry const* entry) +void AchievementMgr::RemoveCriteriaProgress(AchievementCriteria const* entry) { if (!entry) return; @@ -429,7 +430,7 @@ void AchievementMgr::RemoveCriteriaProgress(AchievementCriteriaEntry const* e } template<> -void AchievementMgr::RemoveCriteriaProgress(AchievementCriteriaEntry const* entry) +void AchievementMgr::RemoveCriteriaProgress(AchievementCriteria const* entry) { if (!entry) return; @@ -474,27 +475,28 @@ void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaTypes type, if (GetOwner()->IsGameMaster()) return; - AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type); - for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) + AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type); + for (AchievementCriteria const* achievementCriteria : achievementCriteriaList) { - AchievementCriteriaEntry const* achievementCriteria = (*i); - - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->achievement); - if (!achievement) - continue; - - // don't update already completed criteria if not forced or achievement already complete - if ((IsCompletedCriteria(achievementCriteria, achievement) && !evenIfCriteriaComplete) || HasAchieved(achievement->ID)) + if (achievementCriteria->Entry->FailEvent != miscValue1 || (achievementCriteria->Entry->FailAsset && achievementCriteria->Entry->FailAsset != miscValue2)) continue; - for (uint8 j = 0; j < MAX_CRITERIA_REQUIREMENTS; ++j) - if (achievementCriteria->additionalRequirements[j].additionalRequirement_type == miscValue1 && - (!achievementCriteria->additionalRequirements[j].additionalRequirement_value || - achievementCriteria->additionalRequirements[j].additionalRequirement_value == miscValue2)) + AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(achievementCriteria->ID); + bool allComplete = true; + for (AchievementCriteriaTree const* tree : *trees) + { + // don't update already completed criteria if not forced or achievement already complete + if (!(IsCompletedCriteriaTree(tree) && !evenIfCriteriaComplete) || !HasAchieved(tree->Achievement->ID)) { - RemoveCriteriaProgress(achievementCriteria); + allComplete = false; break; } + } + + if (allComplete) + continue; + + RemoveCriteriaProgress(achievementCriteria); } } @@ -545,7 +547,6 @@ template void AchievementMgr::SaveToDB(SQLTransaction& /*trans*/) { } - template<> void AchievementMgr::SaveToDB(SQLTransaction& trans) { @@ -571,6 +572,7 @@ void AchievementMgr::SaveToDB(SQLTransaction& trans) } } + /* if (!m_criteriaProgress.empty()) { for (CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter != m_criteriaProgress.end(); ++iter) @@ -596,6 +598,7 @@ void AchievementMgr::SaveToDB(SQLTransaction& trans) iter->second.changed = false; } } + */ } template<> @@ -626,6 +629,7 @@ void AchievementMgr::SaveToDB(SQLTransaction& trans) guidstr.str(""); } + /* for (CriteriaProgressMap::const_iterator itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr) { if (!itr->second.changed) @@ -641,11 +645,11 @@ void AchievementMgr::SaveToDB(SQLTransaction& trans) stmt->setUInt16(1, itr->first); stmt->setUInt64(2, itr->second.counter); stmt->setUInt32(3, itr->second.date); - stmt->setUInt64(4, itr->second.CompletedGUID.GetCounter()); + stmt->setUInt64(4, itr->second.PlayerGUID.GetCounter()); trans->Append(stmt); } + */ } - template void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult) { @@ -682,6 +686,7 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, P while (achievementResult->NextRow()); } + /* if (criteriaResult) { time_t now = time(NULL); @@ -692,7 +697,7 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, P uint64 counter = fields[1].GetUInt64(); time_t date = time_t(fields[2].GetUInt32()); - AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(id); + AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(id); if (!criteria) { // we will remove not existed criteria for all characters @@ -705,7 +710,7 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, P continue; } - if (criteria->timeLimit && time_t(date + criteria->timeLimit) < now) + if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now) continue; CriteriaProgress& progress = m_criteriaProgress[id]; @@ -715,6 +720,7 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, P } while (criteriaResult->NextRow()); } + */ } template<> @@ -745,6 +751,7 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Pr while (achievementResult->NextRow()); } + /* if (criteriaResult) { time_t now = time(NULL); @@ -756,7 +763,7 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Pr time_t date = time_t(fields[2].GetUInt32()); ObjectGuid::LowType guid = fields[3].GetUInt64(); - AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(id); + AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(id); if (!criteria) { // we will remove not existed criteria for all guilds @@ -768,16 +775,17 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Pr continue; } - if (criteria->timeLimit && time_t(date + criteria->timeLimit) < now) + if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now) continue; CriteriaProgress& progress = m_criteriaProgress[id]; progress.counter = counter; progress.date = date; - progress.CompletedGUID = ObjectGuid::Create(guid); + progress.PlayerGUID = ObjectGuid::Create(guid); progress.changed = false; } while (criteriaResult->NextRow()); } + */ } template @@ -840,7 +848,7 @@ void AchievementMgr::Reset() } while (!m_criteriaProgress.empty()) - if (AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(m_criteriaProgress.begin()->first)) + if (AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(m_criteriaProgress.begin()->first)) RemoveCriteriaProgress(criteria); _achievementPoints = 0; @@ -883,12 +891,13 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievemen GetOwner()->VisitNearbyWorldObject(sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _worker); } - WorldPacket data(SMSG_ACHIEVEMENT_EARNED, 8+4+8); - data << GetOwner()->GetPackGUID(); - data << uint32(achievement->ID); - data.AppendPackedTime(time(NULL)); - data << uint32(0); // does not notify player ingame - GetOwner()->SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); + WorldPackets::Achievement::AchievementEarned achievementEarned; + achievementEarned.Sender = GetOwner()->GetGUID(); + achievementEarned.Earner = GetOwner()->GetGUID(); + achievementEarned.EarnerNativeRealm = achievementEarned.EarnerVirtualRealm = GetVirtualRealmAddress(); + achievementEarned.AchievementID = achievement->ID; + achievementEarned.Time = time(NULL); + GetOwner()->SendMessageToSetInRange(achievementEarned.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); } template<> @@ -921,39 +930,38 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achiev } template -void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* /*entry*/, CriteriaProgress const* /*progress*/, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const +void AchievementMgr::SendCriteriaUpdate(AchievementCriteria const* /*criteria*/, CriteriaProgress const* /*progress*/, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const { } template<> -void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const +void AchievementMgr::SendCriteriaUpdate(AchievementCriteria const* criteria, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const { - WorldPacket data(SMSG_CRITERIA_UPDATE, 8 + 4 + 8); - data << uint32(entry->ID); + WorldPackets::Achievement::CriteriaUpdate criteriaUpdate; - // the counter is packed like a packed Guid - data.AppendPackedUInt64(progress->counter); + criteriaUpdate.CriteriaID = criteria->ID; + criteriaUpdate.Quantity = progress->counter; + criteriaUpdate.PlayerGUID = GetOwner()->GetGUID(); + if (criteria->Entry->StartTimer) + criteriaUpdate.Flags = timedCompleted ? 1 : 0; // 1 is for keeping the counter at 0 in client - data << GetOwner()->GetPackGUID(); - if (!entry->timeLimit) - data << uint32(0); - else - data << uint32(timedCompleted ? 1 : 0); // this are some flags, 1 is for keeping the counter at 0 in client - data.AppendPackedTime(progress->date); - data << uint32(timeElapsed); // time elapsed in seconds - data << uint32(0); // unk - SendPacket(&data); + criteriaUpdate.Flags = 0; + criteriaUpdate.CurrentTime = progress->date; + criteriaUpdate.ElapsedTime = timeElapsed; + criteriaUpdate.CreationTime = 0; + + SendPacket(criteriaUpdate.Write()); } template<> -void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const +void AchievementMgr::SendCriteriaUpdate(AchievementCriteria const* entry, CriteriaProgress const* progress, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const { /* //will send response to criteria progress request WorldPacket data(SMSG_GUILD_CRITERIA_DATA, 3 + 1 + 1 + 8 + 8 + 4 + 4 + 4 + 4 + 4); ObjectGuid counter(0, progress->counter); // for accessing every byte individually - ObjectGuid guid = progress->CompletedGUID; + ObjectGuid guid = progress->PlayerGUID; data.WriteBits(1, 21); data.WriteBit(counter[4]); @@ -1016,7 +1024,7 @@ void AchievementMgr::SendAllTrackedCriterias(Player* receiver, std::set::iterator itr = trackedCriterias.begin(); itr != trackedCriterias.end(); ++itr) { - AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteria(*itr); + AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteriaTree(*itr); CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(entry->ID); if (progress == m_criteriaProgress.end()) @@ -1032,14 +1040,14 @@ void AchievementMgr::SendAllTrackedCriterias(Player* receiver, std::set::iterator itr = trackedCriterias.begin(); itr != trackedCriterias.end(); ++itr) { - AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteria(*itr); + AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteriaTree(*itr); CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(entry->ID); if (progress == m_criteriaProgress.end()) continue; counter.SetRawValue(progress->second.counter); - guid = progress->second.CompletedGUID; + guid = progress->second.PlayerGUID; criteriaBits.WriteBit(counter[4]); criteriaBits.WriteBit(counter[1]); @@ -1102,18 +1110,6 @@ void AchievementMgr::CheckAllAchievementCriteria(Player* referencePlayer) UpdateAchievementCriteria(AchievementCriteriaTypes(i), 0, 0, 0, NULL, referencePlayer); } -static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = {1057, 1107, 1108}; -static const uint32 achievIdForDungeon[][4] = -{ - // ach_cr_id, is_dungeon, is_raid, is_heroic_dungeon - { 321, true, true, true }, - { 916, false, true, false }, - { 917, false, true, false }, - { 918, true, false, false }, - { 2219, false, false, true }, - { 0, false, false, false } -}; - // Helper function to avoid having to specialize template for a 800 line long function template static bool IsGuild() { return false; } template<> bool IsGuild() { return true; } @@ -1151,18 +1147,12 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, if (IsGuild() && !sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED)) return; - AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, IsGuild()); - for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) + AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, IsGuild()); + for (AchievementCriteria const* achievementCriteria : achievementCriteriaList) { - AchievementCriteriaEntry const* achievementCriteria = (*i); - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->achievement); - if (!achievement) - { - TC_LOG_ERROR("achievement", "UpdateAchievementCriteria: Achievement %u not found!", achievementCriteria->achievement); - continue; - } + AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(achievementCriteria->ID); - if (!CanUpdateCriteria(achievementCriteria, achievement, miscValue1, miscValue2, miscValue3, unit, referencePlayer)) + if (!CanUpdateCriteria(achievementCriteria, trees, miscValue1, miscValue2, miscValue3, unit, referencePlayer)) continue; // requirements not found in the dbc @@ -1253,11 +1243,11 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, SetCriteriaProgress(achievementCriteria, referencePlayer->getLevel(), referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: - if (uint32 skillvalue = referencePlayer->GetBaseSkillValue(achievementCriteria->reach_skill_level.skillID)) + if (uint32 skillvalue = referencePlayer->GetBaseSkillValue(achievementCriteria->Entry->Asset.SkillID)) SetCriteriaProgress(achievementCriteria, skillvalue, referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: - if (uint32 maxSkillvalue = referencePlayer->GetPureMaxSkillValue(achievementCriteria->learn_skill_level.skillID)) + if (uint32 maxSkillvalue = referencePlayer->GetPureMaxSkillValue(achievementCriteria->Entry->Asset.SkillID)) SetCriteriaProgress(achievementCriteria, maxSkillvalue, referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT: @@ -1301,7 +1291,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, for (RewardedQuestSet::const_iterator itr = rewQuests.begin(); itr != rewQuests.end(); ++itr) { Quest const* quest = sObjectMgr->GetQuestTemplate(*itr); - if (quest && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->complete_quests_in_zone.zoneID) + if (quest && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->Entry->Asset.ZoneID) ++counter; } SetCriteriaProgress(achievementCriteria, counter, referencePlayer); @@ -1325,7 +1315,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, break; case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: { - int32 reputation = referencePlayer->GetReputationMgr().GetReputation(achievementCriteria->gain_reputation.factionID); + int32 reputation = referencePlayer->GetReputationMgr().GetReputation(achievementCriteria->Entry->Asset.FactionID); if (reputation > 0) SetCriteriaProgress(achievementCriteria, reputation, referencePlayer); break; @@ -1343,7 +1333,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first); for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter) { - if (skillIter->second->SkillLine == achievementCriteria->learn_skillline_spell.skillLine) + if (skillIter->second->SkillLine == achievementCriteria->Entry->Asset.SkillID) spellCount++; } } @@ -1368,7 +1358,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, { SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first); for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter) - if (skillIter->second->SkillLine == achievementCriteria->learn_skill_line.skillLine) + if (skillIter->second->SkillLine == achievementCriteria->Entry->Asset.SkillID) spellCount++; } SetCriteriaProgress(achievementCriteria, spellCount, referencePlayer); @@ -1388,7 +1378,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, break; case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING: { - uint32 reqTeamType = achievementCriteria->highest_team_rating.teamtype; + uint32 reqTeamType = achievementCriteria->Entry->Asset.TeamType; if (miscValue1) { @@ -1418,7 +1408,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, } case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: { - uint32 reqTeamType = achievementCriteria->highest_personal_rating.teamtype; + uint32 reqTeamType = achievementCriteria->Entry->Asset.TeamType; if (miscValue1) { @@ -1472,19 +1462,22 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, break; // Not implemented yet :( } - if (IsCompletedCriteria(achievementCriteria, achievement)) - CompletedCriteriaFor(achievement, referencePlayer); - - // check again the completeness for SUMM and REQ COUNT achievements, - // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria - if (achievement->Flags & ACHIEVEMENT_FLAG_SUMM) - if (IsCompletedAchievement(achievement)) - CompletedAchievement(achievement, referencePlayer); - - if (AchievementEntryList const* achRefList = sAchievementMgr->GetAchievementByReferencedId(achievement->ID)) - for (AchievementEntryList::const_iterator itr = achRefList->begin(); itr != achRefList->end(); ++itr) - if (IsCompletedAchievement(*itr)) - CompletedAchievement(*itr, referencePlayer); + for (AchievementCriteriaTree const* tree : *trees) + { + if (IsCompletedCriteriaTree(tree)) + CompletedCriteriaFor(tree->Achievement, referencePlayer); + + // check again the completeness for SUMM and REQ COUNT achievements, + // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria + if (tree->Achievement->Flags & ACHIEVEMENT_FLAG_SUMM) + if (IsCompletedAchievement(tree->Achievement)) + CompletedAchievement(tree->Achievement, referencePlayer); + + if (AchievementEntryList const* achRefList = sAchievementMgr->GetAchievementByReferencedId(tree->Achievement->ID)) + for (AchievementEntry const* refAchievement : *achRefList) + if (IsCompletedAchievement(refAchievement)) + CompletedAchievement(refAchievement, referencePlayer); + } } } @@ -1497,8 +1490,9 @@ template<> uint32 GetInstanceId(Player* player) { return player->GetInstanceId(); } template -bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement) +bool AchievementMgr::IsCompletedCriteriaTree(AchievementCriteriaTree const* tree) { + AchievementEntry const* achievement = tree->Achievement; if (!achievement) return false; @@ -1513,116 +1507,109 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achi return false; } + uint64 requiredCount = tree->Entry->Amount; + uint64 completedCount = 0; + uint32 op = tree->Entry->Operator; + bool hasAll = true; + + // Check criteria we depend on first + for (AchievementCriteriaTree const* node : tree->Children) + { + if (IsCompletedCriteriaTree(node)) + ++completedCount; + else + hasAll = false; + + if (op & ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ANY && completedCount >= requiredCount) + { + if (!tree->Criteria) + return true; + + break; + } + } + + if (op & ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ANY && completedCount < requiredCount) + return false; + + if (op & ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ALL && !hasAll) + return false; + + if (!tree->Criteria) + return true; + + return IsCompletedCriteria(tree->Criteria, requiredCount); +} + +template +bool AchievementMgr::IsCompletedCriteria(AchievementCriteria const* achievementCriteria, uint64 requiredAmount) +{ CriteriaProgress const* progress = GetCriteriaProgress(achievementCriteria); if (!progress) return false; - switch (AchievementCriteriaTypes(achievementCriteria->type)) + switch (AchievementCriteriaTypes(achievementCriteria->Entry->Type)) { case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - return progress->counter >= achievementCriteria->win_bg.winCount; case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - return progress->counter >= achievementCriteria->kill_creature.creatureCount; case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL: - return progress->counter >= achievementCriteria->reach_level.level; case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: - return progress->counter >= achievementCriteria->reach_skill_level.skillLevel; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: - return progress->counter >= 1; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT: - return progress->counter >= achievementCriteria->complete_quest_count.totalQuestCount; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: - return progress->counter >= achievementCriteria->complete_daily_quest_daily.numberOfDays; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: - return progress->counter >= achievementCriteria->complete_quests_in_zone.questCount; case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: - return progress->counter >= achievementCriteria->healing_done.count; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: - return progress->counter >= achievementCriteria->complete_daily_quest.questCount; case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: - return progress->counter >= achievementCriteria->fall_without_dying.fallHeight; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: - return progress->counter >= 1; case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: - return progress->counter >= achievementCriteria->be_spell_target.spellCount; case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: - return progress->counter >= achievementCriteria->cast_spell.castCount; case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: - return progress->counter >= achievementCriteria->bg_objective.completeCount; case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: - return progress->counter >= achievementCriteria->honorable_kill_at_area.killCount; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: - return progress->counter >= 1; case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL: - return progress->counter >= achievementCriteria->honorable_kill.killCount; case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: - return progress->counter >= achievementCriteria->own_item.itemCount; case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: - return progress->counter >= achievementCriteria->win_rated_arena.count; case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: - return progress->counter >= achievementCriteria->highest_personal_rating.PersonalRating; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: - return progress->counter >= (achievementCriteria->learn_skill_level.skillLevel * 75); case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: - return progress->counter >= achievementCriteria->use_item.itemCount; case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: - return progress->counter >= achievementCriteria->loot_item.itemCount; - case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: - return progress->counter >= 1; case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: - return progress->counter >= achievementCriteria->buy_bank_slot.numberOfSlots; case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: - return progress->counter >= achievementCriteria->gain_reputation.reputationAmount; case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: - return progress->counter >= achievementCriteria->gain_exalted_reputation.numberOfExaltedFactions; case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP: - return progress->counter >= achievementCriteria->visit_barber.numberOfVisits; case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: - return progress->counter >= achievementCriteria->equip_epic_item.count; case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: - return progress->counter >= achievementCriteria->roll_greed_on_loot.count; case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: - return progress->counter >= achievementCriteria->hk_class.count; case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: - return progress->counter >= achievementCriteria->hk_race.count; case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: - return progress->counter >= achievementCriteria->do_emote.count; case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: - return progress->counter >= achievementCriteria->equip_item.count; case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: - return progress->counter >= achievementCriteria->quest_reward_money.goldInCopper; case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY: - return progress->counter >= achievementCriteria->loot_money.goldInCopper; case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: - return progress->counter >= achievementCriteria->use_gameobject.useCount; case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: - return progress->counter >= achievementCriteria->special_pvp_kill.killCount; case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: - return progress->counter >= achievementCriteria->fish_in_gameobject.lootCount; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: - return progress->counter >= achievementCriteria->learn_skillline_spell.spellCount; case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: - return progress->counter >= achievementCriteria->win_duel.duelCount; case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: - return progress->counter >= achievementCriteria->loot_type.lootTypeCount; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE: - return progress->counter >= achievementCriteria->learn_skill_line.spellCount; - case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: - return progress->counter >= 9000; case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: - return progress->counter >= achievementCriteria->use_lfg.dungeonsComplete; case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: - return progress->counter >= achievementCriteria->get_killing_blow.killCount; case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: - return progress->counter >= achievementCriteria->currencyGain.count; + return progress->counter >= requiredAmount; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: + case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: + return progress->counter >= 1; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: + return progress->counter >= (requiredAmount * 75); + case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: + return progress->counter >= 9000; case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: - return achievementCriteria->win_arena.count && progress->counter >= achievementCriteria->win_arena.count; + return requiredAmount && progress->counter >= requiredAmount; case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: return true; // handle all statistic-only criteria here @@ -1679,6 +1666,20 @@ void AchievementMgr::CompletedCriteriaFor(AchievementEntry const* achievement CompletedAchievement(achievement, referencePlayer); } +template +uint64 AchievementMgr::GetTotalCriteriaTreeProgress(AchievementCriteriaTree const* criteriaTree) +{ + uint64 progress = 0; + if (criteriaTree->Criteria) + if (CriteriaProgress const* criteriaProgress = GetCriteriaProgress(criteriaTree->Criteria)) + progress += criteriaProgress->counter; + + for (AchievementCriteriaTree const* node : criteriaTree->Children) + progress += GetTotalCriteriaTreeProgress(node); + + return progress; +} + template bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) { @@ -1686,64 +1687,20 @@ bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) if (entry->Flags & ACHIEVEMENT_FLAG_COUNTER) return false; - // for achievement with referenced achievement criterias get from referenced and counter from self - uint32 achievementForTestId = entry->SharesCriteria ? entry->SharesCriteria : entry->ID; - uint32 achievementForTestCount = entry->MinimumCriteria; - - AchievementCriteriaEntryList const* cList = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementForTestId); - if (!cList) + AchievementCriteriaTree const* tree = sAchievementMgr->GetAchievementCriteriaTree(entry->CriteriaTree); + if (!tree) return false; - uint64 count = 0; // For SUMM achievements, we have to count the progress of each criteria of the achievement. // Oddly, the target count is NOT contained in the achievement, but in each individual criteria if (entry->Flags & ACHIEVEMENT_FLAG_SUMM) - { - for (AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr) - { - AchievementCriteriaEntry const* criteria = *itr; - - CriteriaProgress const* progress = GetCriteriaProgress(criteria); - if (!progress) - continue; - - count += progress->counter; - - // for counters, field4 contains the main count requirement - if (count >= criteria->raw.count) - return true; - } - return false; - } - - // Default case - need complete all or - bool completed_all = true; - for (AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr) - { - AchievementCriteriaEntry const* criteria = *itr; - - bool completed = IsCompletedCriteria(criteria, entry); - - // found an uncompleted criteria, but DONT return false yet - there might be a completed criteria with ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL - if (completed) - ++count; - else - completed_all = false; + return GetTotalCriteriaTreeProgress(tree) >= tree->Entry->Amount; - // completed as have req. count of completed criterias - if (achievementForTestCount > 0 && achievementForTestCount <= count) - return true; - } - - // all criterias completed requirement - if (completed_all && achievementForTestCount == 0) - return true; - - return false; + return IsCompletedCriteriaTree(tree); } template -CriteriaProgress* AchievementMgr::GetCriteriaProgress(AchievementCriteriaEntry const* entry) +CriteriaProgress* AchievementMgr::GetCriteriaProgress(AchievementCriteria const* entry) { CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID); @@ -1754,25 +1711,44 @@ CriteriaProgress* AchievementMgr::GetCriteriaProgress(AchievementCriteriaEntr } template -void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype) +void AchievementMgr::SetCriteriaProgress(AchievementCriteria const* criteria, uint64 changeValue, Player* referencePlayer, ProgressType ptype) { // Don't allow to cheat - doing timed achievements without timer active - TimedAchievementMap::iterator timedIter = m_timedAchievements.find(entry->ID); - if (entry->timeLimit && timedIter == m_timedAchievements.end()) - return; + AchievementCriteriaTreeList const* trees = nullptr; + if (criteria->Entry->StartTimer) + { + trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(criteria->ID); + if (!trees) + return; + + bool hasTreeForTimed = false; + for (AchievementCriteriaTree const* tree : *trees) + { + auto timedIter = m_timedAchievements.find(tree->ID); + if (timedIter != m_timedAchievements.end()) + { + hasTreeForTimed = true; + break; + } + + } + + if (!hasTreeForTimed) + return; + } TC_LOG_DEBUG("achievement", "SetCriteriaProgress(%u, " UI64FMTD ") for (%s)", - entry->ID, changeValue, GetOwner()->GetGUID().ToString().c_str()); + criteria->ID, changeValue, GetOwner()->GetGUID().ToString().c_str()); - CriteriaProgress* progress = GetCriteriaProgress(entry); + CriteriaProgress* progress = GetCriteriaProgress(criteria); if (!progress) { // not create record for 0 counter but allow it for timed achievements // we will need to send 0 progress to client to start the timer - if (changeValue == 0 && !entry->timeLimit) + if (changeValue == 0 && !criteria->Entry->StartTimer) return; - progress = &m_criteriaProgress[entry->ID]; + progress = &m_criteriaProgress[criteria->ID]; progress->counter = changeValue; } else @@ -1796,7 +1772,7 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entr } // not update (not mark as changed) if counter will have same value - if (progress->counter == newValue && !entry->timeLimit) + if (progress->counter == newValue && !criteria->Entry->StartTimer) return; progress->counter = newValue; @@ -1804,25 +1780,30 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entr progress->changed = true; progress->date = time(NULL); // set the date to the latest update. + progress->PlayerGUID = referencePlayer->GetGUID(); - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(entry->achievement); uint32 timeElapsed = 0; - bool criteriaComplete = IsCompletedCriteria(entry, achievement); - if (entry->timeLimit) + if (criteria->Entry->StartTimer) { - // Client expects this in packet - timeElapsed = entry->timeLimit - (timedIter->second/IN_MILLISECONDS); + ASSERT(trees); - // Remove the timer, we wont need it anymore - if (criteriaComplete) - m_timedAchievements.erase(timedIter); - } + for (AchievementCriteriaTree const* tree : *trees) + { + auto timedIter = m_timedAchievements.find(tree->ID); + if (timedIter != m_timedAchievements.end()) + { + // Client expects this in packet + timeElapsed = criteria->Entry->StartTimer - (timedIter->second / IN_MILLISECONDS); - if (criteriaComplete && achievement->Flags & ACHIEVEMENT_FLAG_SHOW_CRITERIA_MEMBERS && !progress->CompletedGUID) - progress->CompletedGUID = referencePlayer->GetGUID(); + // Remove the timer, we wont need it anymore + if (IsCompletedCriteriaTree(tree)) + m_timedAchievements.erase(timedIter); + } + } + } - SendCriteriaUpdate(entry, progress, timeElapsed, criteriaComplete); + SendCriteriaUpdate(criteria, progress, timeElapsed, true); } template @@ -1835,8 +1816,10 @@ void AchievementMgr::UpdateTimedAchievements(uint32 timeDiff) // Time is up, remove timer and reset progress if (itr->second <= timeDiff) { - AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteria(itr->first); - RemoveCriteriaProgress(entry); + AchievementCriteriaTree const* criteriaTree = sAchievementMgr->GetAchievementCriteriaTree(itr->first); + if (criteriaTree->Criteria) + RemoveCriteriaProgress(criteriaTree->Criteria); + m_timedAchievements.erase(itr++); } else @@ -1856,46 +1839,51 @@ void AchievementMgr::StartTimedAchievement(AchievementCriteriaTimedTypes /*ty template<> void AchievementMgr::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost /* = 0 */) { - AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); - for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) + AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); + for (AchievementCriteria const* criteria : achievementCriteriaList) { - if ((*i)->timedCriteriaMiscId != entry) + if (criteria->Entry->StartAsset != entry) continue; - AchievementEntry const* achievement = sAchievementMgr->GetAchievement((*i)->achievement); - if (m_timedAchievements.find((*i)->ID) == m_timedAchievements.end() && !IsCompletedCriteria(*i, achievement)) + AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(criteria->ID); + bool canStart = false; + for (AchievementCriteriaTree const* tree : *trees) { - // Start the timer - if ((*i)->timeLimit * IN_MILLISECONDS > timeLost) + if (m_timedAchievements.find(tree->ID) == m_timedAchievements.end() && !IsCompletedCriteriaTree(tree)) { - m_timedAchievements[(*i)->ID] = (*i)->timeLimit * IN_MILLISECONDS - timeLost; - - // and at client too - SetCriteriaProgress(*i, 0, GetOwner(), PROGRESS_SET); + // Start the timer + if (criteria->Entry->StartTimer * IN_MILLISECONDS > timeLost) + { + m_timedAchievements[tree->ID] = criteria->Entry->StartTimer * IN_MILLISECONDS - timeLost; + canStart = true; + } } } + + if (!canStart) + continue; + + // and at client too + SetCriteriaProgress(criteria, 0, GetOwner(), PROGRESS_SET); } } template void AchievementMgr::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) { - AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); - for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) + AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); + for (AchievementCriteria const* criteria : achievementCriteriaList) { - if ((*i)->timedCriteriaMiscId != entry) + if (criteria->Entry->StartAsset != entry) continue; - TimedAchievementMap::iterator timedIter = m_timedAchievements.find((*i)->ID); - // We don't have timer for this achievement - if (timedIter == m_timedAchievements.end()) - continue; + AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(criteria->ID); + // Remove the timer from all trees + for (AchievementCriteriaTree const* tree : *trees) + m_timedAchievements.erase(tree->ID); // remove progress - RemoveCriteriaProgress(*i); - - // Remove the timer - m_timedAchievements.erase(timedIter); + RemoveCriteriaProgress(criteria); } } @@ -2036,75 +2024,38 @@ struct VisibleAchievementPred template void AchievementMgr::SendAllAchievementData(Player* /*receiver*/) const { - /* VisibleAchievementPred isVisible; - size_t numCriteria = m_criteriaProgress.size(); - size_t numAchievements = std::count_if(m_completedAchievements.begin(), m_completedAchievements.end(), isVisible); - ByteBuffer criteriaData(numCriteria * (4 + 4 + 4 + 4 + 8 + 8)); - ObjectGuid guid = GetOwner()->GetGUID(); - ObjectGuid counter; + WorldPackets::Achievement::AllAchievements achievementData; + achievementData.Earned.reserve(m_completedAchievements.size()); + achievementData.Progress.reserve(m_criteriaProgress.size()); - WorldPacket data(SMSG_ALL_ACHIEVEMENT_DATA, 4 + numAchievements * (4 + 4) + 4 + numCriteria * (4 + 4 + 4 + 4 + 8 + 8)); - data.WriteBits(numCriteria, 21); - for (CriteriaProgressMap::const_iterator itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr) + for (auto itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) { - counter.SetRawValue(itr->second.counter); - - data.WriteBit(guid[4]); - data.WriteBit(counter[3]); - data.WriteBit(guid[5]); - data.WriteBit(counter[0]); - data.WriteBit(counter[6]); - data.WriteBit(guid[3]); - data.WriteBit(guid[0]); - data.WriteBit(counter[4]); - data.WriteBit(guid[2]); - data.WriteBit(counter[7]); - data.WriteBit(guid[7]); - data.WriteBits(0u, 2); - data.WriteBit(guid[6]); - data.WriteBit(counter[2]); - data.WriteBit(counter[1]); - data.WriteBit(counter[5]); - data.WriteBit(guid[1]); + if (!isVisible(*itr)) + continue; - criteriaData.WriteByteSeq(guid[3]); - criteriaData.WriteByteSeq(counter[5]); - criteriaData.WriteByteSeq(counter[6]); - criteriaData.WriteByteSeq(guid[4]); - criteriaData.WriteByteSeq(guid[6]); - criteriaData.WriteByteSeq(counter[2]); - criteriaData << uint32(0); // timer 2 - criteriaData.WriteByteSeq(guid[2]); - criteriaData << uint32(itr->first); // criteria id - criteriaData.WriteByteSeq(guid[5]); - criteriaData.WriteByteSeq(counter[0]); - criteriaData.WriteByteSeq(counter[3]); - criteriaData.WriteByteSeq(counter[1]); - criteriaData.WriteByteSeq(counter[4]); - criteriaData.WriteByteSeq(guid[0]); - criteriaData.WriteByteSeq(guid[7]); - criteriaData.WriteByteSeq(counter[7]); - criteriaData << uint32(0); // timer 1 - criteriaData.AppendPackedTime(itr->second.date); // criteria date - criteriaData.WriteByteSeq(guid[1]); + WorldPackets::Achievement::EarnedAchievement earned; + earned.Id = itr->first; + earned.Date = itr->second.date; + earned.Owner = GetOwner()->GetGUID(); + earned.VirtualRealmAddress = earned.NativeRealmAddress = GetVirtualRealmAddress(); + achievementData.Earned.push_back(earned); } - data.WriteBits(numAchievements, 23); - data.FlushBits(); - data.append(criteriaData); - - for (CompletedAchievementMap::const_iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) + for (auto itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr) { - if (!isVisible(*itr)) - continue; - - data << uint32(itr->first); - data.AppendPackedTime(itr->second.date); + WorldPackets::Achievement::CriteriaProgress progress; + progress.Id = itr->first; + progress.Quantity = itr->second.counter; + progress.Player = itr->second.PlayerGUID; + progress.Flags = 0; + progress.Date = itr->second.date; + progress.TimeFromStart = 0; + progress.TimeFromCreate = 0; + achievementData.Progress.push_back(progress); } - SendPacket(&data); - */ + SendPacket(achievementData.Write()); } template<> @@ -2227,7 +2178,7 @@ void AchievementMgr::SendAchievementInfo(Player* receiver, uint32 achieve { /* //will send response to criteria progress request - AchievementCriteriaEntryList const* criteria = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementId); + AchievementCriteriaTreeList const* criteria = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementId); if (!criteria) { // send empty packet @@ -2243,7 +2194,7 @@ void AchievementMgr::SendAchievementInfo(Player* receiver, uint32 achieve uint32 numCriteria = 0; ByteBuffer criteriaData(criteria->size() * (8 + 8 + 4 + 4 + 4)); ByteBuffer criteriaBits(criteria->size() * (8 + 8) / 8); - for (AchievementCriteriaEntryList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr) + for (AchievementCriteriaTreeList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr) { uint32 criteriaId = (*itr)->ID; CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(criteriaId); @@ -2255,7 +2206,7 @@ void AchievementMgr::SendAchievementInfo(Player* receiver, uint32 achieve criteriaBits.WriteBits(numCriteria, 21); - for (AchievementCriteriaEntryList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr) + for (AchievementCriteriaTreeList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr) { uint32 criteriaId = (*itr)->ID; CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(criteriaId); @@ -2263,7 +2214,7 @@ void AchievementMgr::SendAchievementInfo(Player* receiver, uint32 achieve continue; counter.SetRawValue(progress->second.counter); - guid = progress->second.CompletedGUID; + guid = progress->second.PlayerGUID; criteriaBits.WriteBit(counter[4]); criteriaBits.WriteBit(counter[1]); @@ -2321,55 +2272,65 @@ bool AchievementMgr::HasAchieved(uint32 achievementId) const } template -bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) +bool AchievementMgr::CanUpdateCriteria(AchievementCriteria const* criteria, AchievementCriteriaTreeList const* trees, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) { if (DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, criteria->ID, NULL)) { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Disabled", - criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); + TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Disabled", + criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type)); return false; } - if (achievement->MapID != -1 && referencePlayer->GetMapId() != uint32(achievement->MapID)) + bool treeRequirementPassed = false; + for (AchievementCriteriaTree const* tree : *trees) { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Wrong map", - criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); - return false; - } + if (HasAchieved(tree->Achievement->ID)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s Achievement %u) Achievement already earned", + criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Achievement->ID); + continue; + } - if ((achievement->Faction == ACHIEVEMENT_FACTION_HORDE && referencePlayer->GetTeam() != HORDE) || - (achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && referencePlayer->GetTeam() != ALLIANCE)) - { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Wrong faction", - criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); - return false; + if (tree->Achievement->MapID != -1 && referencePlayer->GetMapId() != uint32(tree->Achievement->MapID)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s Achievement %u) Wrong map", + criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Achievement->ID); + continue; + } + + if ((tree->Achievement->Faction == ACHIEVEMENT_FACTION_HORDE && referencePlayer->GetTeam() != HORDE) || + (tree->Achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && referencePlayer->GetTeam() != ALLIANCE)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s Achievement %u) Wrong faction", + criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Achievement->ID); + continue; + } + + treeRequirementPassed = true; + break; } - if (IsCompletedCriteria(criteria, achievement)) - { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Is Completed", - criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); + if (!treeRequirementPassed) return false; - } if (!RequirementsSatisfied(criteria, miscValue1, miscValue2, miscValue3, unit, referencePlayer)) { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Requirements not satisfied", - criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); + TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Requirements not satisfied", + criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type)); return false; } - if (!AdditionalRequirementsSatisfied(criteria, miscValue1, miscValue2, unit, referencePlayer)) + if (criteria->Modifier && !AdditionalRequirementsSatisfied(criteria->Modifier, miscValue1, miscValue2, unit, referencePlayer)) { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Additional requirements not satisfied", - criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); + TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Additional requirements not satisfied", + criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type)); return false; } if (!ConditionsSatisfied(criteria, referencePlayer)) { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Conditions not satisfied", - criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); + TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Conditions not satisfied", + criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type)); return false; } @@ -2377,35 +2338,32 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criter } template -bool AchievementMgr::ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* referencePlayer) const +bool AchievementMgr::ConditionsSatisfied(AchievementCriteria const* criteria, Player* referencePlayer) const { - for (uint32 i = 0; i < MAX_CRITERIA_REQUIREMENTS; ++i) - { - if (!criteria->additionalRequirements[i].additionalRequirement_type) - continue; + if (!criteria->Entry->FailEvent) + return true; - switch (criteria->additionalRequirements[i].additionalRequirement_type) - { - case ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP: - if (referencePlayer->GetMapId() != criteria->additionalRequirements[i].additionalRequirement_value) - return false; - break; - case ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP: - if (referencePlayer->GetGroup()) - return false; - break; - default: - break; - } + switch (criteria->Entry->FailEvent) + { + case ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP: + if (!referencePlayer->InBattleground()) + return false; + break; + case ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP: + if (referencePlayer->GetGroup()) + return false; + break; + default: + break; } return true; } template -bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* achievementCriteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const +bool AchievementMgr::RequirementsSatisfied(AchievementCriteria const* achievementCriteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const { - switch (AchievementCriteriaTypes(achievementCriteria->type)) + switch (AchievementCriteriaTypes(achievementCriteria->Entry->Type)) { case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: @@ -2460,57 +2418,36 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: break; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: - if (m_completedAchievements.find(achievementCriteria->complete_achievement.linkedAchievement) == m_completedAchievements.end()) + if (m_completedAchievements.find(achievementCriteria->Entry->Asset.AchievementID) == m_completedAchievements.end()) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - if (!miscValue1 || achievementCriteria->win_bg.bgMapID != referencePlayer->GetMapId()) + if (!miscValue1 || achievementCriteria->Entry->Asset.MapID != referencePlayer->GetMapId()) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - if (!miscValue1 || achievementCriteria->kill_creature.creatureID != miscValue1) + if (!miscValue1 || achievementCriteria->Entry->Asset.CreatureID != miscValue1) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: - // update at loading or specific skill update - if (miscValue1 && miscValue1 != achievementCriteria->reach_skill_level.skillID) - return false; - break; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: // update at loading or specific skill update - if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_level.skillID) + if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SkillID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: - if (miscValue1 && miscValue1 != achievementCriteria->complete_quests_in_zone.zoneID) + if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.ZoneID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: - if (!miscValue1 || referencePlayer->GetMapId() != achievementCriteria->complete_battleground.mapID) - return false; - break; case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: - if (!miscValue1 || referencePlayer->GetMapId() != achievementCriteria->death_at_map.mapID) + if (!miscValue1 || referencePlayer->GetMapId() != achievementCriteria->Entry->Asset.MapID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_DEATH: { if (!miscValue1) return false; - // skip wrong arena achievements, if not achievIdByArenaSlot then normal total death counter - bool notfit = false; - for (int j = 0; j < MAX_ARENA_SLOT; ++j) - { - if (achievIdByArenaSlot[j] == achievementCriteria->achievement) - { - Battleground* bg = referencePlayer->GetBattleground(); - if (!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j) - notfit = true; - break; - } - } - if (notfit) - return false; break; } case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON: @@ -2522,45 +2459,13 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac if (!map || !map->IsDungeon()) return false; - // search case - bool found = false; - for (int j = 0; achievIdForDungeon[j][0]; ++j) - { - if (achievIdForDungeon[j][0] == achievementCriteria->achievement) - { - if (map->IsRaid()) - { - // if raid accepted (ignore difficulty) - if (!achievIdForDungeon[j][2]) - break; // for - } - else if (referencePlayer->GetDungeonDifficulty() == DIFFICULTY_NORMAL) - { - // dungeon in normal mode accepted - if (!achievIdForDungeon[j][1]) - break; // for - } - else - { - // dungeon in heroic mode accepted - if (!achievIdForDungeon[j][3]) - break; // for - } - - found = true; - break; // for - } - } - if (!found) - return false; - //FIXME: work only for instances where max == min for players - if (((InstanceMap*)map)->GetMaxPlayers() != achievementCriteria->death_in_dungeon.manLimit) + if (((InstanceMap*)map)->GetMaxPlayers() != achievementCriteria->Entry->Asset.GroupSize) return false; break; } case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE: - if (!miscValue1 || miscValue1 != achievementCriteria->killed_by_creature.creatureEntry) + if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.CreatureID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER: @@ -2568,7 +2473,7 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac return false; break; case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM: - if (!miscValue1 || miscValue2 != achievementCriteria->death_from.type) + if (!miscValue1 || miscValue2 != achievementCriteria->Entry->Asset.DamageType) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: @@ -2576,13 +2481,13 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac // if miscValues != 0, it contains the questID. if (miscValue1) { - if (miscValue1 != achievementCriteria->complete_quest.questID) + if (miscValue1 != achievementCriteria->Entry->Asset.QuestID) return false; } else { // login case. - if (!referencePlayer->GetQuestRewardStatus(achievementCriteria->complete_quest.questID)) + if (!referencePlayer->GetQuestRewardStatus(achievementCriteria->Entry->Asset.QuestID)) return false; } @@ -2593,42 +2498,37 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac } case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: - if (!miscValue1 || miscValue1 != achievementCriteria->be_spell_target.spellID) - return false; - break; case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: - if (!miscValue1 || miscValue1 != achievementCriteria->cast_spell.spellID) + if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.SpellID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: - if (miscValue1 && miscValue1 != achievementCriteria->learn_spell.spellID) + if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SpellID) return false; - if (!referencePlayer->HasSpell(achievementCriteria->learn_spell.spellID)) + if (!referencePlayer->HasSpell(achievementCriteria->Entry->Asset.SpellID)) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: // miscValue1 = itemId - miscValue2 = count of item loot // miscValue3 = loot_type (note: 0 = LOOT_CORPSE and then it ignored) - if (!miscValue1 || !miscValue2 || !miscValue3 || miscValue3 != achievementCriteria->loot_type.lootType) + if (!miscValue1 || !miscValue2 || !miscValue3 || miscValue3 != achievementCriteria->Entry->Asset.LootType) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: - if (miscValue1 && achievementCriteria->own_item.itemID != miscValue1) + if (miscValue1 && achievementCriteria->Entry->Asset.ItemID != miscValue1) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: - if (!miscValue1 || achievementCriteria->use_item.itemID != miscValue1) - return false; - break; case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: - if (!miscValue1 || miscValue1 != achievementCriteria->own_item.itemID) + case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: + if (!miscValue1 || achievementCriteria->Entry->Asset.ItemID != miscValue1) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: { - WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->explore_area.areaReference); + WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->Entry->Asset.WorldMapOverlayID); if (!worldOverlayEntry) break; @@ -2658,19 +2558,19 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac break; } case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: - if (miscValue1 && miscValue1 != achievementCriteria->gain_reputation.factionID) + if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.FactionID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: // miscValue1 = itemid miscValue2 = itemSlot - if (!miscValue1 || miscValue2 != achievementCriteria->equip_epic_item.itemSlot) + if (!miscValue1 || miscValue2 != achievementCriteria->Entry->Asset.ItemSlot) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: { // miscValue1 = itemid miscValue2 = diced value - if (!miscValue1 || miscValue2 != achievementCriteria->roll_greed_on_loot.rollValue) + if (!miscValue1 || miscValue2 != achievementCriteria->Entry->Asset.RollValue) return false; ItemTemplate const* proto = sObjectMgr->GetItemTemplate(uint32(miscValue1)); @@ -2679,7 +2579,7 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac break; } case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: - if (!miscValue1 || miscValue1 != achievementCriteria->do_emote.emoteID) + if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.EmoteID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: @@ -2687,9 +2587,9 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac if (!miscValue1) return false; - if (achievementCriteria->additionalRequirements[0].additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP) + if (achievementCriteria->Entry->FailEvent == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP) { - if (referencePlayer->GetMapId() != achievementCriteria->additionalRequirements[0].additionalRequirement_value) + if (!referencePlayer->InBattleground()) return false; // map specific case (BG in fact) expected player targeted damage/heal @@ -2697,21 +2597,13 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac return false; } break; - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: - // miscValue1 = item_id - if (!miscValue1 || miscValue1 != achievementCriteria->equip_item.itemID) - return false; - break; case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: - if (!miscValue1 || miscValue1 != achievementCriteria->use_gameobject.goEntry) - return false; - break; case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: - if (!miscValue1 || miscValue1 != achievementCriteria->fish_in_gameobject.goEntry) + if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.GameObjectID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: - if (miscValue1 && miscValue1 != achievementCriteria->learn_skillline_spell.skillLine) + if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SkillID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: @@ -2725,32 +2617,32 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac break; } case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE: - if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_line.skillLine) + if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SkillID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: - if (!miscValue1 || miscValue1 != achievementCriteria->hk_class.classID) + if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.ClassID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: - if (!miscValue1 || miscValue1 != achievementCriteria->hk_race.raceID) + if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.RaceID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: - if (!miscValue1 || miscValue1 != achievementCriteria->bg_objective.objectiveId) + if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.ObjectiveId) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: - if (!miscValue1 || miscValue1 != achievementCriteria->honorable_kill_at_area.areaID) + if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.AreaID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: if (!miscValue1 || !miscValue2 || int64(miscValue2) < 0 - || miscValue1 != achievementCriteria->currencyGain.currency) + || miscValue1 != achievementCriteria->Entry->Asset.CurrencyID) return false; break; case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: - if (miscValue1 != achievementCriteria->win_arena.mapID) + if (miscValue1 != achievementCriteria->Entry->Asset.MapID) return false; break; default: @@ -2760,137 +2652,148 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac } template -bool AchievementMgr::AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 /*miscValue2*/, Unit const* unit, Player* referencePlayer) const +bool AchievementMgr::AdditionalRequirementsSatisfied(ModifierTreeNode const* tree, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const { - for (uint8 i = 0; i < MAX_ADDITIONAL_CRITERIA_CONDITIONS; ++i) - { - uint32 reqType = criteria->additionalConditionType[i]; - uint32 reqValue = criteria->additionalConditionValue[i]; + for (ModifierTreeNode const* node : tree->Children) + if (!AdditionalRequirementsSatisfied(node, miscValue1, miscValue2, unit, referencePlayer)) + return false; + + uint32 reqType = tree->Entry->Type; + if (!reqType) + return true; + + uint32 reqValue = tree->Entry->Asset[0]; - switch (AchievementCriteriaAdditionalCondition(reqType)) + switch (AchievementCriteriaAdditionalCondition(reqType)) + { + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY: // 4 + if (!unit || unit->GetEntry() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER: // 5 + if (!unit || unit->GetTypeId() != TYPEID_PLAYER) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD: // 6 + if (!unit || unit->IsAlive()) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY: // 7 + if (!unit || !referencePlayer->IsHostileTo(unit)) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA: // 8 + if (!referencePlayer->HasAura(reqValue)) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA: // 10 + if (!unit || !unit->HasAura(reqValue)) + return false; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE: // 11 + if (!unit || !unit->HasAuraType(AuraType(reqValue))) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN: // 14 { - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY: // 4 - if (!unit || unit->GetEntry() != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER: // 5 - if (!unit || unit->GetTypeId() != TYPEID_PLAYER) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD: // 6 - if (!unit || unit->IsAlive()) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY: // 7 - if (!unit || !referencePlayer->IsHostileTo(unit)) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA: // 8 - if (!referencePlayer->HasAura(reqValue)) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA: // 10 - if (!unit || !unit->HasAura(reqValue)) - return false; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE: // 11 - if (!unit || !unit->HasAuraType(AuraType(reqValue))) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN: // 14 - { - // miscValue1 is itemid - ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); - if (!item || item->GetQuality() < reqValue) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS: // 15 - { - // miscValue1 is itemid - ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); - if (!item || item->GetQuality() != reqValue) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE: // 17 - { - uint32 zoneId, areaId; - referencePlayer->GetZoneAndAreaId(zoneId, areaId); - if (zoneId != reqValue && areaId != reqValue) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE: // 18 - { - if (!unit) - return false; - uint32 zoneId, areaId; - unit->GetZoneAndAreaId(zoneId, areaId); - if (zoneId != reqValue && areaId != reqValue) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY: // 20 - if (uint32(referencePlayer->GetMap()->GetDifficulty()) != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE: // 25 - if (referencePlayer->getRace() != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS: // 26 - if (referencePlayer->getClass() != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE: // 27 - if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getRace() != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS: // 28 - if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getClass() != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS: // 29 - if (referencePlayer->GetGroup() && referencePlayer->GetGroup()->GetMembersCount() >= reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE: // 30 - { - if (!unit) - return false; - Creature const* const creature = unit->ToCreature(); - if (!creature || creature->GetCreatureType() != reqValue) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP: // 32 - if (referencePlayer->GetMapId() != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX: // 38 - // miscValue1 is title's bit index - if (miscValue1 != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL: // 39 - if (referencePlayer->getLevel() != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL: // 40 - if (!unit || unit->getLevel() != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE: // 41 - if (!unit || unit->GetZoneId() != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW: // 46 - if (!unit || unit->GetHealthPct() >= reqValue) - return false; - break; - default: - break; + // miscValue1 is itemid + ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); + if (!item || item->GetQuality() < reqValue) + return false; + break; } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS: // 15 + { + // miscValue1 is itemid + ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); + if (!item || item->GetQuality() != reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE: // 17 + { + uint32 zoneId, areaId; + referencePlayer->GetZoneAndAreaId(zoneId, areaId); + if (zoneId != reqValue && areaId != reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE: // 18 + { + if (!unit) + return false; + uint32 zoneId, areaId; + unit->GetZoneAndAreaId(zoneId, areaId); + if (zoneId != reqValue && areaId != reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY: // 20 + if (uint32(referencePlayer->GetMap()->GetDifficulty()) != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE: + { + Battleground* bg = referencePlayer->GetBattleground(); + if (!bg || !bg->isArena() || bg->GetArenaType() != reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE: // 25 + if (referencePlayer->getRace() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS: // 26 + if (referencePlayer->getClass() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE: // 27 + if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getRace() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS: // 28 + if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getClass() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS: // 29 + if (referencePlayer->GetGroup() && referencePlayer->GetGroup()->GetMembersCount() >= reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE: // 30 + { + if (!unit) + return false; + Creature const* const creature = unit->ToCreature(); + if (!creature || creature->GetCreatureType() != reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP: // 32 + if (referencePlayer->GetMapId() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX: // 38 + // miscValue1 is title's bit index + if (miscValue1 != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL: // 39 + if (referencePlayer->getLevel() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL: // 40 + if (!unit || unit->getLevel() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE: // 41 + if (!unit || unit->GetZoneId() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW: // 46 + if (!unit || unit->GetHealthPct() >= reqValue) + return false; + break; + default: + break; } return true; } @@ -3134,35 +3037,166 @@ template class AchievementMgr; template class AchievementMgr; //========================================================== +AchievementGlobalMgr::~AchievementGlobalMgr() +{ + for (AchievementCriteriaTreeMap::iterator itr = _achievementCriteriaTrees.begin(); itr != _achievementCriteriaTrees.end(); ++itr) + delete itr->second; + + for (AchievementCriteriaMap::iterator itr = _achievementCriteria.begin(); itr != _achievementCriteria.end(); ++itr) + delete itr->second; + + for (ModifierTreeMap::iterator itr = _criteriaModifiers.begin(); itr != _criteriaModifiers.end(); ++itr) + delete itr->second; +} + +void AchievementGlobalMgr::LoadAchievementCriteriaModifiersTree() +{ + uint32 oldMSTime = getMSTime(); + + if (sModifierTreeStore.GetNumRows() == 0) + { + TC_LOG_ERROR("server.loading", ">> Loaded 0 achievement criteria modifiers."); + return; + } + + // Load modifier tree nodes + for (uint32 i = 0; i < sModifierTreeStore.GetNumRows(); ++i) + { + ModifierTreeEntry const* tree = sModifierTreeStore.LookupEntry(i); + if (!tree) + continue; + + ModifierTreeNode* node = new ModifierTreeNode(); + node->Entry = tree; + _criteriaModifiers[node->Entry->ID] = node; + } + + // Build tree + for (auto itr = _criteriaModifiers.begin(); itr != _criteriaModifiers.end(); ++itr) + { + if (!itr->second->Entry->Parent) + continue; + + auto parent = _criteriaModifiers.find(itr->second->Entry->Parent); + if (parent != _criteriaModifiers.end()) + parent->second->Children.push_back(itr->second); + } + + TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria modifiers in %u ms", uint32(_criteriaModifiers.size()), GetMSTimeDiffToNow(oldMSTime)); +} + void AchievementGlobalMgr::LoadAchievementCriteriaList() { uint32 oldMSTime = getMSTime(); - if (sAchievementCriteriaStore.GetNumRows() == 0) + if (sCriteriaTreeStore.GetNumRows() == 0) { TC_LOG_ERROR("server.loading", ">> Loaded 0 achievement criteria."); return; } + std::unordered_map achievementCriteriaTreeIds; + for (uint32 i = 0; i < sAchievementStore.GetNumRows(); ++i) + if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(i)) + if (achievement->CriteriaTree) + achievementCriteriaTreeIds[achievement->CriteriaTree] = achievement; + + // Load criteria tree nodes + for (uint32 i = 0; i < sCriteriaTreeStore.GetNumRows(); ++i) + { + CriteriaTreeEntry const* tree = sCriteriaTreeStore.LookupEntry(i); + if (!tree) + continue; + + // Find linked achievement + auto achievementItr = achievementCriteriaTreeIds.find(tree->ID); + CriteriaTreeEntry const* cur = tree; + while (achievementItr == achievementCriteriaTreeIds.end()) + { + if (!tree->Parent) + break; + + cur = sCriteriaTreeStore.LookupEntry(cur->Parent); + if (!cur) + break; + + achievementItr = achievementCriteriaTreeIds.find(cur->ID); + } + + if (achievementItr == achievementCriteriaTreeIds.end()) + continue; + + AchievementCriteriaTree* achievementCriteriaTree = new AchievementCriteriaTree(); + achievementCriteriaTree->ID = i; + achievementCriteriaTree->Achievement = achievementItr->second; + achievementCriteriaTree->Entry = tree; + achievementCriteriaTree->Criteria = nullptr; + + _achievementCriteriaTrees[achievementCriteriaTree->Entry->ID] = achievementCriteriaTree; + if (sCriteriaStore.LookupEntry(tree->CriteriaID)) + _achievementCriteriaTreeByCriteria[tree->CriteriaID].push_back(achievementCriteriaTree); + } + + // Build tree + for (auto itr = _achievementCriteriaTrees.begin(); itr != _achievementCriteriaTrees.end(); ++itr) + { + if (!itr->second->Entry->Parent) + continue; + + auto parent = _achievementCriteriaTrees.find(itr->second->Entry->Parent); + if (parent != _achievementCriteriaTrees.end()) + parent->second->Children.push_back(itr->second); + } + + // Load criteria uint32 criterias = 0; uint32 guildCriterias = 0; - for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId) + for (uint32 i = 0; i < sCriteriaStore.GetNumRows(); ++i) { - AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(entryId); + CriteriaEntry const* criteria = sCriteriaStore.LookupEntry(i); if (!criteria) continue; - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(criteria->achievement); - - m_AchievementCriteriaListByAchievement[criteria->achievement].push_back(criteria); + auto treeItr = _achievementCriteriaTreeByCriteria.find(i); + if (treeItr == _achievementCriteriaTreeByCriteria.end()) + continue; - if (achievement && achievement->Flags & ACHIEVEMENT_FLAG_GUILD) - ++guildCriterias, m_GuildAchievementCriteriasByType[criteria->type].push_back(criteria); + AchievementCriteria* achievementCriteria = new AchievementCriteria(); + achievementCriteria->ID = i; + achievementCriteria->Entry = criteria; + auto mod = _criteriaModifiers.find(criteria->ModifierTreeId); + if (mod != _criteriaModifiers.end()) + achievementCriteria->Modifier = mod->second; else - ++criterias, m_AchievementCriteriasByType[criteria->type].push_back(criteria); + achievementCriteria->Modifier = nullptr; + + _achievementCriteria[achievementCriteria->ID] = achievementCriteria; + + bool isGuild = false, isPlayer = false; + for (AchievementCriteriaTree const* tree : treeItr->second) + { + const_cast(tree)->Criteria = achievementCriteria; - if (criteria->timeLimit) - m_AchievementCriteriasByTimedType[criteria->timedCriteriaStartType].push_back(criteria); + if (tree->Achievement->Flags & ACHIEVEMENT_FLAG_GUILD) + isGuild = true; + else + isPlayer = true; + } + + if (isGuild) + { + ++guildCriterias; + _guildAchievementCriteriasByType[criteria->Type].push_back(achievementCriteria); + } + + if (isPlayer) + { + ++criterias; + _achievementCriteriasByType[criteria->Type].push_back(achievementCriteria); + } + + if (criteria->StartTimer) + _achievementCriteriasByTimedType[criteria->StartEvent].push_back(achievementCriteria); } TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria and %u guild achievement crieteria in %u ms", criterias, guildCriterias, GetMSTimeDiffToNow(oldMSTime)); @@ -3186,13 +3220,13 @@ void AchievementGlobalMgr::LoadAchievementReferenceList() if (!achievement || !achievement->SharesCriteria) continue; - m_AchievementListByReferencedId[achievement->SharesCriteria].push_back(achievement); + _achievementListByReferencedId[achievement->SharesCriteria].push_back(achievement); ++count; } // Once Bitten, Twice Shy (10 player) - Icecrown Citadel if (AchievementEntry const* achievement = sAchievementMgr->GetAchievement(4539)) - const_cast(achievement)->MapID = 631; // Correct map requirement (currently has Ulduar) + const_cast(achievement)->MapID = 631; // Correct map requirement (currently has Ulduar); 6.0.3 note - it STILL has ulduar requirement TC_LOG_INFO("server.loading", ">> Loaded %u achievement references in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } @@ -3201,7 +3235,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() { uint32 oldMSTime = getMSTime(); - m_criteriaDataMap.clear(); // need for reload case + _criteriaDataMap.clear(); // need for reload case QueryResult result = WorldDatabase.Query("SELECT criteria_id, type, value1, value2, ScriptName FROM achievement_criteria_data"); @@ -3218,7 +3252,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() Field* fields = result->Fetch(); uint32 criteria_id = fields[0].GetUInt32(); - AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(criteria_id); + AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(criteria_id); if (!criteria) { @@ -3243,7 +3277,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() continue; // this will allocate empty data set storage - AchievementCriteriaDataSet& dataSet = m_criteriaDataMap[criteria_id]; + AchievementCriteriaDataSet& dataSet = _criteriaDataMap[criteria_id]; dataSet.SetCriteriaId(criteria_id); // add real data only for not NONE data types @@ -3288,18 +3322,18 @@ void AchievementGlobalMgr::LoadCompletedAchievements() continue; } else if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) - m_allCompletedAchievements[achievementId] = uint32(0xFFFFFFFF); + _allCompletedAchievements[achievementId] = uint32(0xFFFFFFFF); } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu realm first completed achievements in %u ms", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %lu realm first completed achievements in %u ms", (unsigned long)_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime)); } void AchievementGlobalMgr::LoadRewards() { uint32 oldMSTime = getMSTime(); - m_achievementRewards.clear(); // need for reload case + _achievementRewards.clear(); // need for reload case // 0 1 2 3 4 5 6 7 QueryResult result = WorldDatabase.Query("SELECT entry, title_A, title_H, item, sender, subject, text, mailTemplate FROM achievement_reward"); @@ -3406,7 +3440,7 @@ void AchievementGlobalMgr::LoadRewards() } } - m_achievementRewards[entry] = reward; + _achievementRewards[entry] = reward; ++count; } while (result->NextRow()); @@ -3418,7 +3452,7 @@ void AchievementGlobalMgr::LoadRewardLocales() { uint32 oldMSTime = getMSTime(); - m_achievementRewardLocales.clear(); // need for reload case + _achievementRewardLocales.clear(); // need for reload case QueryResult result = WorldDatabase.Query("SELECT entry, subject_loc1, text_loc1, subject_loc2, text_loc2, subject_loc3, text_loc3, subject_loc4, text_loc4, " "subject_loc5, text_loc5, subject_loc6, text_loc6, subject_loc7, text_loc7, subject_loc8, text_loc8" @@ -3436,13 +3470,13 @@ void AchievementGlobalMgr::LoadRewardLocales() uint32 entry = fields[0].GetUInt32(); - if (m_achievementRewards.find(entry) == m_achievementRewards.end()) + if (_achievementRewards.find(entry) == _achievementRewards.end()) { TC_LOG_ERROR("sql.sql", "Table `locales_achievement_reward` (Entry: %u) has locale strings for non-existing achievement reward.", entry); continue; } - AchievementRewardLocale& data = m_achievementRewardLocales[entry]; + AchievementRewardLocale& data = _achievementRewardLocales[entry]; for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) { @@ -3453,7 +3487,7 @@ void AchievementGlobalMgr::LoadRewardLocales() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u achievement reward locale strings in %u ms", uint32(m_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u achievement reward locale strings in %u ms", uint32(_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime)); } AchievementEntry const* AchievementGlobalMgr::GetAchievement(uint32 achievementId) const @@ -3461,14 +3495,27 @@ AchievementEntry const* AchievementGlobalMgr::GetAchievement(uint32 achievementI return sAchievementStore.LookupEntry(achievementId); } -AchievementCriteriaEntry const* AchievementGlobalMgr::GetAchievementCriteria(uint32 criteriaId) const +AchievementCriteriaTree const* AchievementGlobalMgr::GetAchievementCriteriaTree(uint32 criteriaTreeId) const { - return sAchievementCriteriaStore.LookupEntry(criteriaId); + auto itr = _achievementCriteriaTrees.find(criteriaTreeId); + if (itr == _achievementCriteriaTrees.end()) + return nullptr; + + return itr->second; +} + +AchievementCriteria const* AchievementGlobalMgr::GetAchievementCriteria(uint32 criteriaId) const +{ + auto itr = _achievementCriteria.find(criteriaId); + if (itr == _achievementCriteria.end()) + return nullptr; + + return itr->second; } void AchievementGlobalMgr::OnInstanceDestroyed(uint32 instanceId) { - for (auto& realmCompletion : m_allCompletedAchievements) + for (auto& realmCompletion : _allCompletedAchievements) if (realmCompletion.second == instanceId) realmCompletion.second = uint32(0xFFFFFFFF); } diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index 90d52cd9101..05b30c73e76 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -32,17 +32,45 @@ class Unit; class Player; class WorldPacket; -typedef std::vector AchievementCriteriaEntryList; -typedef std::vector AchievementEntryList; +struct ModifierTreeNode +{ + ModifierTreeEntry const* Entry; + std::vector Children; +}; + +typedef std::unordered_map ModifierTreeMap; + +struct AchievementCriteria +{ + uint32 ID; + CriteriaEntry const* Entry; + ModifierTreeNode const* Modifier; +}; + +typedef std::vector AchievementCriteriaList; +typedef std::unordered_map AchievementCriteriaMap; -typedef std::unordered_map AchievementCriteriaListByAchievement; -typedef std::unordered_map AchievementListByReferencedId; +struct AchievementCriteriaTree +{ + uint32 ID; + CriteriaTreeEntry const* Entry; + AchievementEntry const* Achievement; + AchievementCriteria const* Criteria; + std::vector Children; +}; + +typedef std::unordered_map AchievementCriteriaTreeMap; +typedef std::vector AchievementCriteriaTreeList; +typedef std::vector AchievementEntryList; +typedef std::unordered_map AchievementCriteriaTreeByCriteriaMap; + +typedef std::unordered_map AchievementListByReferencedId; struct CriteriaProgress { uint64 counter; time_t date; // latest update time. - ObjectGuid CompletedGUID; // GUID of the player that completed this criteria (guild achievements) + ObjectGuid PlayerGUID; // GUID of the player that completed this criteria (guild achievements) bool changed; }; @@ -193,7 +221,7 @@ struct AchievementCriteriaData ScriptId = _scriptId; } - bool IsValid(AchievementCriteriaEntry const* criteria); + bool IsValid(AchievementCriteria const* criteria); bool Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscValue1 = 0) const; }; @@ -276,32 +304,34 @@ class AchievementMgr uint32 GetAchievementPoints() const { return _achievementPoints; } private: void SendAchievementEarned(AchievementEntry const* achievement) const; - void SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const; - CriteriaProgress* GetCriteriaProgress(AchievementCriteriaEntry const* entry); - void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype = PROGRESS_SET); - void RemoveCriteriaProgress(AchievementCriteriaEntry const* entry); + void SendCriteriaUpdate(AchievementCriteria const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const; + CriteriaProgress* GetCriteriaProgress(AchievementCriteria const* entry); + void SetCriteriaProgress(AchievementCriteria const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype = PROGRESS_SET); + void RemoveCriteriaProgress(AchievementCriteria const* entry); void CompletedCriteriaFor(AchievementEntry const* achievement, Player* referencePlayer); - bool IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement); + bool IsCompletedCriteriaTree(AchievementCriteriaTree const* tree); + bool IsCompletedCriteria(AchievementCriteria const* achievementCriteria, uint64 requiredAmount); + uint64 GetTotalCriteriaTreeProgress(AchievementCriteriaTree const* criteriaTree); bool IsCompletedAchievement(AchievementEntry const* entry); - bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer); - void SendPacket(WorldPacket* data) const; + bool CanUpdateCriteria(AchievementCriteria const* criteria, AchievementCriteriaTreeList const* trees, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer); + void SendPacket(WorldPacket const* data) const; - bool ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* referencePlayer) const; - bool RequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const; - bool AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const; + bool ConditionsSatisfied(AchievementCriteria const* criteria, Player* referencePlayer) const; + bool RequirementsSatisfied(AchievementCriteria const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const; + bool AdditionalRequirementsSatisfied(ModifierTreeNode const* parent, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const; T* _owner; CriteriaProgressMap m_criteriaProgress; CompletedAchievementMap m_completedAchievements; typedef std::map TimedAchievementMap; - TimedAchievementMap m_timedAchievements; // Criteria id/time left in MS + TimedAchievementMap m_timedAchievements; // Criteria tree id/time left in MS uint32 _achievementPoints; }; class AchievementGlobalMgr { AchievementGlobalMgr() { } - ~AchievementGlobalMgr() { } + ~AchievementGlobalMgr(); public: static char const* GetCriteriaTypeString(AchievementCriteriaTypes type); @@ -313,50 +343,50 @@ class AchievementGlobalMgr return &instance; } - AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type, bool guild = false) const + AchievementCriteriaTreeList const* GetAchievementCriteriaTreesByCriteria(uint32 criteriaId) const { - return guild ? m_GuildAchievementCriteriasByType[type] : m_AchievementCriteriasByType[type]; + auto itr = _achievementCriteriaTreeByCriteria.find(criteriaId); + return itr != _achievementCriteriaTreeByCriteria.end() ? &itr->second : nullptr; } - AchievementCriteriaEntryList const& GetTimedAchievementCriteriaByType(AchievementCriteriaTimedTypes type) const + AchievementCriteriaList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type, bool guild = false) const { - return m_AchievementCriteriasByTimedType[type]; + return guild ? _guildAchievementCriteriasByType[type] : _achievementCriteriasByType[type]; } - AchievementCriteriaEntryList const* GetAchievementCriteriaByAchievement(uint32 id) const + AchievementCriteriaList const& GetTimedAchievementCriteriaByType(AchievementCriteriaTimedTypes type) const { - AchievementCriteriaListByAchievement::const_iterator itr = m_AchievementCriteriaListByAchievement.find(id); - return itr != m_AchievementCriteriaListByAchievement.end() ? &itr->second : NULL; + return _achievementCriteriasByTimedType[type]; } AchievementEntryList const* GetAchievementByReferencedId(uint32 id) const { - AchievementListByReferencedId::const_iterator itr = m_AchievementListByReferencedId.find(id); - return itr != m_AchievementListByReferencedId.end() ? &itr->second : NULL; + AchievementListByReferencedId::const_iterator itr = _achievementListByReferencedId.find(id); + return itr != _achievementListByReferencedId.end() ? &itr->second : NULL; } AchievementReward const* GetAchievementReward(AchievementEntry const* achievement) const { - AchievementRewards::const_iterator iter = m_achievementRewards.find(achievement->ID); - return iter != m_achievementRewards.end() ? &iter->second : NULL; + AchievementRewards::const_iterator iter = _achievementRewards.find(achievement->ID); + return iter != _achievementRewards.end() ? &iter->second : NULL; } AchievementRewardLocale const* GetAchievementRewardLocale(AchievementEntry const* achievement) const { - AchievementRewardLocales::const_iterator iter = m_achievementRewardLocales.find(achievement->ID); - return iter != m_achievementRewardLocales.end() ? &iter->second : NULL; + AchievementRewardLocales::const_iterator iter = _achievementRewardLocales.find(achievement->ID); + return iter != _achievementRewardLocales.end() ? &iter->second : NULL; } - AchievementCriteriaDataSet const* GetCriteriaDataSet(AchievementCriteriaEntry const* achievementCriteria) const + AchievementCriteriaDataSet const* GetCriteriaDataSet(AchievementCriteria const* achievementCriteria) const { - AchievementCriteriaDataMap::const_iterator iter = m_criteriaDataMap.find(achievementCriteria->ID); - return iter != m_criteriaDataMap.end() ? &iter->second : NULL; + AchievementCriteriaDataMap::const_iterator iter = _criteriaDataMap.find(achievementCriteria->ID); + return iter != _criteriaDataMap.end() ? &iter->second : NULL; } bool IsRealmCompleted(AchievementEntry const* achievement, uint32 instanceId) const { - AllCompletedAchievements::const_iterator itr = m_allCompletedAchievements.find(achievement->ID); - if (itr == m_allCompletedAchievements.end()) + AllCompletedAchievements::const_iterator itr = _allCompletedAchievements.find(achievement->ID); + if (itr == _allCompletedAchievements.end()) return false; if (achievement->Flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL) @@ -370,7 +400,7 @@ class AchievementGlobalMgr if (IsRealmCompleted(achievement, instanceId)) return; - m_allCompletedAchievements[achievement->ID] = instanceId; + _allCompletedAchievements[achievement->ID] = instanceId; } bool IsGroupCriteriaType(AchievementCriteriaTypes type) const @@ -394,6 +424,7 @@ class AchievementGlobalMgr // Removes instanceId as valid id to complete realm first kill achievements void OnInstanceDestroyed(uint32 instanceId); + void LoadAchievementCriteriaModifiersTree(); void LoadAchievementCriteriaList(); void LoadAchievementCriteriaData(); void LoadAchievementReferenceList(); @@ -401,27 +432,31 @@ class AchievementGlobalMgr void LoadRewards(); void LoadRewardLocales(); AchievementEntry const* GetAchievement(uint32 achievementId) const; - AchievementCriteriaEntry const* GetAchievementCriteria(uint32 achievementId) const; + AchievementCriteriaTree const* GetAchievementCriteriaTree(uint32 criteriaTreeId) const; + AchievementCriteria const* GetAchievementCriteria(uint32 criteriaId) const; private: - AchievementCriteriaDataMap m_criteriaDataMap; + AchievementCriteriaDataMap _criteriaDataMap; - // store achievement criterias by type to speed up lookup - AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; - AchievementCriteriaEntryList m_GuildAchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; + AchievementCriteriaTreeMap _achievementCriteriaTrees; + AchievementCriteriaMap _achievementCriteria; + ModifierTreeMap _criteriaModifiers; + + AchievementCriteriaTreeByCriteriaMap _achievementCriteriaTreeByCriteria; - AchievementCriteriaEntryList m_AchievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX]; + // store achievement criterias by type to speed up lookup + AchievementCriteriaList _achievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; + AchievementCriteriaList _guildAchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; - // store achievement criterias by achievement to speed up lookup - AchievementCriteriaListByAchievement m_AchievementCriteriaListByAchievement; + AchievementCriteriaList _achievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX]; // store achievements by referenced achievement id to speed up lookup - AchievementListByReferencedId m_AchievementListByReferencedId; + AchievementListByReferencedId _achievementListByReferencedId; typedef std::map AllCompletedAchievements; - AllCompletedAchievements m_allCompletedAchievements; + AllCompletedAchievements _allCompletedAchievements; - AchievementRewards m_achievementRewards; - AchievementRewardLocales m_achievementRewardLocales; + AchievementRewards _achievementRewards; + AchievementRewardLocales _achievementRewardLocales; }; #define sAchievementMgr AchievementGlobalMgr::instance() diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 3187b5f9f77..8b93ba5222b 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -93,12 +93,6 @@ enum AchievementFlags ACHIEVEMENT_FLAG_SHOW_CRITERIA_MEMBERS = 0x00010000 // }; -enum AchievementCriteriaLimits -{ - MAX_CRITERIA_REQUIREMENTS = 2, - MAX_ADDITIONAL_CRITERIA_CONDITIONS = 3 -}; - enum AchievementCriteriaCondition { ACHIEVEMENT_CRITERIA_CONDITION_NONE = 0, @@ -132,7 +126,7 @@ enum AchievementCriteriaAdditionalCondition ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE = 18, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY = 20, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_YIELDS_XP = 21, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE = 24, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE = 24, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE = 25, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS = 26, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE = 27, @@ -179,6 +173,8 @@ enum AchievementCriteriaTimedTypes ACHIEVEMENT_TIMED_TYPE_CREATURE = 7, // Timer is started by killing creature with entry in timerStartEvent ACHIEVEMENT_TIMED_TYPE_ITEM = 9, // Timer is started by using item with entry in timerStartEvent ACHIEVEMENT_TIMED_TYPE_UNK = 10, // Unknown + ACHIEVEMENT_TIMED_TYPE_UNK_2 = 13, // Unknown + ACHIEVEMENT_TIMED_TYPE_SCENARIO_STAGE = 14, // Timer is started by changing stages in a scenario ACHIEVEMENT_TIMED_TYPE_MAX }; @@ -299,7 +295,13 @@ enum AchievementCriteriaTypes ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE = 139 //struct { uint32 count; } Guild Challenge }; -#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 140 +#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 188 + +enum AchievementCriteriaTreeOperator +{ + ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ALL = 4, + ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ANY = 8 +}; enum AreaFlags { diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index b801fd7b3f3..6647fa08fc2 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -60,7 +60,6 @@ static AreaFlagByMapID sAreaFlagByMapID; // for instances wit static WMOAreaInfoByTripple sWMOAreaInfoByTripple; DBCStorage sAchievementStore(Achievementfmt); -DBCStorage sAchievementCriteriaStore(AchievementCriteriafmt); DBCStorage sAreaTriggerStore(AreaTriggerEntryfmt); DBCStorage sArmorLocationStore(ArmorLocationfmt); DBCStorage sAuctionHouseStore(AuctionHouseEntryfmt); @@ -85,6 +84,8 @@ DBCStorage sCreatureFamilyStore(CreatureFamilyfmt); DBCStorage sCreatureModelDataStore(CreatureModelDatafmt); DBCStorage sCreatureSpellDataStore(CreatureSpellDatafmt); DBCStorage sCreatureTypeStore(CreatureTypefmt); +DBCStorage sCriteriaStore(Criteriafmt); +DBCStorage sCriteriaTreeStore(CriteriaTreefmt); DBCStorage sCurrencyTypesStore(CurrencyTypesfmt); uint32 PowersByClass[MAX_CLASSES][MAX_POWERS]; @@ -163,6 +164,7 @@ DBCStorage sMapStore(MapEntryfmt); DBCStorage sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading MapDifficultyMap sMapDifficultyMap; +DBCStorage sModifierTreeStore(ModifierTreefmt); DBCStorage sMovieStore(MovieEntryfmt); DBCStorage sMountCapabilityStore(MountCapabilityfmt); DBCStorage sMountTypeStore(MountTypefmt); @@ -240,19 +242,13 @@ typedef std::list StoreProblemList; uint32 DBCFileCount = 0; -static bool LoadDBC_assert_print(uint32 fsize, uint32 rsize, const std::string& filename) -{ - TC_LOG_ERROR("misc", "Size of '%s' set by format string (%u) not equal size of C++ structure (%u).", filename.c_str(), fsize, rsize); - - // ASSERT must fail after function call - return false; -} - template inline void LoadDBC(uint32& availableDbcLocales, StoreProblemList& errors, DBCStorage& storage, std::string const& dbcPath, std::string const& filename, std::string const* customFormat = NULL, std::string const* customIndexName = NULL) { // compatibility format and C++ structure sizes - ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename)); + ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T), + "Size of '%s' set by format string (%u) not equal size of C++ structure (%u).", + filename.c_str(), DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T)); ++DBCFileCount; std::string dbcFilename = dbcPath + filename; @@ -298,7 +294,9 @@ template inline void LoadGameTable(StoreProblemList& errors, std::string const& tableName, GameTable& storage, std::string const& dbcPath, std::string const& filename) { // compatibility format and C++ structure sizes - ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename)); + ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T), + "Size of '%s' set by format string (%u) not equal size of C++ structure (%u).", + filename.c_str(), DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T)); ++DBCFileCount; std::string dbcFilename = dbcPath + filename; @@ -365,8 +363,6 @@ void LoadDBCStores(const std::string& dataPath) } LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc"/*, &CustomAchievementfmt, &CustomAchievementIndex*/);//19116 - // TODO: 6.x remove this and update achievement system with new dbcs - //LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTriggerStore, dbcPath, "AreaTrigger.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sAreaGroupStore, dbcPath, "AreaGroup.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sAuctionHouseStore, dbcPath, "AuctionHouse.dbc");//19116 @@ -415,6 +411,8 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureModelDataStore, dbcPath, "CreatureModelData.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureSpellDataStore, dbcPath, "CreatureSpellData.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureTypeStore, dbcPath, "CreatureType.dbc");//19116 + LoadDBC(availableDbcLocales, bad_dbc_files, sCriteriaStore, dbcPath, "Criteria.dbc");//19342 + LoadDBC(availableDbcLocales, bad_dbc_files, sCriteriaTreeStore, dbcPath, "CriteriaTree.dbc");//19342 LoadDBC(availableDbcLocales, bad_dbc_files, sCurrencyTypesStore, dbcPath, "CurrencyTypes.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sDestructibleModelDataStore, dbcPath, "DestructibleModelData.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sDungeonEncounterStore, dbcPath, "DungeonEncounter.dbc");//19116 @@ -499,6 +497,7 @@ void LoadDBCStores(const std::string& dataPath) sMapDifficultyMap[MAKE_PAIR32(entry->MapID, entry->DifficultyID)] = MapDifficulty(entry->RaidDuration, entry->MaxPlayers, entry->Message_lang[0] > 0); sMapDifficultyStore.Clear(); + LoadDBC(availableDbcLocales, bad_dbc_files, sModifierTreeStore, dbcPath, "ModifierTree.dbc");//19342 LoadDBC(availableDbcLocales, bad_dbc_files, sMountCapabilityStore, dbcPath, "MountCapability.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sMountTypeStore, dbcPath, "MountType.dbc");//19116 diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 0c25e359483..92770e2e618 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -131,7 +131,6 @@ private: }; extern DBCStorage sAchievementStore; -extern DBCStorage sAchievementCriteriaStore; extern DBCStorage sAreaStore;// recommend access using functions extern DBCStorage sAreaGroupStore; extern DBCStorage sAreaTriggerStore; @@ -156,6 +155,8 @@ extern DBCStorage sCreatureFamilyStore; extern DBCStorage sCreatureModelDataStore; extern DBCStorage sCreatureSpellDataStore; extern DBCStorage sCreatureTypeStore; +extern DBCStorage sCriteriaStore; +extern DBCStorage sCriteriaTreeStore; extern DBCStorage sCurrencyTypesStore; extern DBCStorage sDestructibleModelDataStore; extern DBCStorage sDungeonEncounterStore; @@ -217,6 +218,7 @@ extern DBCStorage sLockStore; extern DBCStorage sMailTemplateStore; extern DBCStorage sMapStore; extern DBCStorage sMinorTalentStore; +extern DBCStorage sModifierTreeStore; extern DBCStorage sMountCapabilityStore; extern DBCStorage sMountTypeStore; extern DBCStorage sNameGenStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index a03f6370c62..32bd3c35fee 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -54,7 +54,7 @@ struct AchievementEntry //char* Reward_lang; // 11 uint32 MinimumCriteria; // 12 - need this count of completed criterias (own or referenced achievement criterias) uint32 SharesCriteria; // 13 - referenced achievement (counting of all completed criterias) - //uint32 CriteriaTree; // 14 + uint32 CriteriaTree; // 14 }; //19116 @@ -66,474 +66,6 @@ struct AchievementCategoryEntry //uint32 UIOrder; // 3 }; -struct AchievementCriteriaEntry -{ - uint32 ID; // 0 - uint32 achievement; // 1 - uint32 type; // 2 - union - { - // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0 - /// @todo also used for player deaths.. - struct - { - uint32 creatureID; // 3 - uint64 creatureCount; // 4 - } kill_creature; - - // ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1 - struct - { - uint32 bgMapID; // 3 - uint64 winCount; // 4 - } win_bg; - - // ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5 - // ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL = 125 - struct - { - uint32 unused; // 3 - uint64 level; // 4 - } reach_level; - - // ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7 - struct - { - uint32 skillID; // 3 - uint64 skillLevel; // 4 - } reach_skill_level; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8 - struct - { - uint32 linkedAchievement; // 3 - } complete_achievement; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9 - struct - { - uint32 unused; // 3 - uint64 totalQuestCount; // 4 - } complete_quest_count; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10 - struct - { - uint32 unused; // 3 - uint64 numberOfDays; // 4 - } complete_daily_quest_daily; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11 - struct - { - uint32 zoneID; // 3 - uint64 questCount; // 4 - } complete_quests_in_zone; - - // ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12 - struct - { - uint32 currency; - uint64 count; - } currencyGain; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14 - struct - { - uint32 unused; // 3 - uint64 questCount; // 4 - } complete_daily_quest; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15 - struct - { - uint32 mapID; // 3 - } complete_battleground; - - // ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16 - struct - { - uint32 mapID; // 3 - } death_at_map; - - // ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18 - struct - { - uint32 manLimit; // 3 - } death_in_dungeon; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19 - struct - { - uint32 groupSize; // 3 can be 5, 10 or 25 - } complete_raid; - - // ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20 - struct - { - uint32 creatureEntry; // 3 - } killed_by_creature; - - // ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24 - struct - { - uint32 unused; // 3 - uint64 fallHeight; // 4 - } fall_without_dying; - - // ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26 - struct - { - uint32 type; // 3, see enum EnviromentalDamage - } death_from; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27 - struct - { - uint32 questID; // 3 - uint64 questCount; // 4 - } complete_quest; - - // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28 - // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69 - struct - { - uint32 spellID; // 3 - uint64 spellCount; // 4 - } be_spell_target; - - // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29 - // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110 - struct - { - uint32 spellID; // 3 - uint64 castCount; // 4 - } cast_spell; - - // ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE - struct - { - uint32 objectiveId; // 3 - uint64 completeCount; // 4 - } bg_objective; - - // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31 - struct - { - uint32 areaID; // 3 Reference to AreaTable.dbc - uint64 killCount; // 4 - } honorable_kill_at_area; - - // ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32 - struct - { - uint32 mapID; // 3 Reference to Map.dbc - uint64 count; // 4 Number of times that the arena must be won. - } win_arena; - - // ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33 - struct - { - uint32 mapID; // 3 Reference to Map.dbc - } play_arena; - - // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34 - struct - { - uint32 spellID; // 3 Reference to Map.dbc - } learn_spell; - - // ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36 - struct - { - uint32 itemID; // 3 - uint64 itemCount; // 4 - } own_item; - - // ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37 - struct - { - uint32 unused; // 3 - uint64 count; // 4 - } win_rated_arena; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38 - struct - { - uint32 teamtype; // 3 {2, 3, 5} - } highest_team_rating; - - // ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING = 39 - struct - { - uint32 teamtype; // 3 {2, 3, 5} - uint64 teamrating; // 4 - } reach_team_rating; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39 - struct - { - uint32 teamtype; // 3 {2, 3, 5} - uint64 PersonalRating; // 4 - } highest_personal_rating; - - // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40 - struct - { - uint32 skillID; // 3 - uint64 skillLevel; // 4 apprentice=1, journeyman=2, expert=3, artisan=4, master=5, grand master=6 - } learn_skill_level; - - // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41 - struct - { - uint32 itemID; // 3 - uint64 itemCount; // 4 - } use_item; - - // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42 - struct - { - uint32 itemID; // 3 - uint64 itemCount; // 4 - } loot_item; - - // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43 - struct - { - /// @todo This rank is _NOT_ the index from AreaTable.dbc - uint32 areaReference; // 3 - } explore_area; - - // ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44 - struct - { - /// @todo This rank is _NOT_ the index from CharTitles.dbc - uint32 rank; // 3 - } own_rank; - - // ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45 - struct - { - uint32 unused; // 3 - uint64 numberOfSlots; // 4 - } buy_bank_slot; - - // ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46 - struct - { - uint32 factionID; // 3 - uint64 reputationAmount; // 4 Total reputation amount, so 42000 = exalted - } gain_reputation; - - // ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION= 47 - struct - { - uint32 unused; // 3 - uint64 numberOfExaltedFactions; // 4 - } gain_exalted_reputation; - - // ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48 - struct - { - uint32 unused; // 3 - uint64 numberOfVisits; // 4 - } visit_barber; - - // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49 - /// @todo where is the required itemlevel stored? - struct - { - uint32 itemSlot; // 3 - uint64 count; // 4 - } equip_epic_item; - - // ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50 - struct - { - uint32 rollValue; // 3 - uint64 count; // 4 - } roll_need_on_loot; - // ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51 - struct - { - uint32 rollValue; // 3 - uint64 count; // 4 - } roll_greed_on_loot; - - // ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52 - struct - { - uint32 classID; // 3 - uint64 count; // 4 - } hk_class; - - // ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53 - struct - { - uint32 raceID; // 3 - uint64 count; // 4 - } hk_race; - - // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54 - /// @todo where is the information about the target stored? - struct - { - uint32 emoteID; // 3 enum TextEmotes - uint64 count; // 4 count of emotes, always required special target or requirements - } do_emote; - // ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13 - // ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55 - // ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56 - struct - { - uint32 unused; // 3 - uint64 count; // 4 - } healing_done; - - // ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56 - struct - { - uint32 unused; - uint64 killCount; - } get_killing_blow; - - // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57 - struct - { - uint32 itemID; // 3 - uint64 count; // 4 - } equip_item; - - // ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD= 62 - struct - { - uint32 unused; // 3 - uint64 goldInCopper; // 4 - } quest_reward_money; - - // ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67 - struct - { - uint32 unused; // 3 - uint64 goldInCopper; // 4 - } loot_money; - - // ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68 - struct - { - uint32 goEntry; // 3 - uint64 useCount; // 4 - } use_gameobject; - - // ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70 - /// @todo are those special criteria stored in the dbc or do we have to add another sql table? - struct - { - uint32 unused; // 3 - uint64 killCount; // 4 - } special_pvp_kill; - - // ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72 - struct - { - uint32 goEntry; // 3 - uint64 lootCount; // 4 - } fish_in_gameobject; - - // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75 - struct - { - uint32 skillLine; // 3 - uint64 spellCount; // 4 - } learn_skillline_spell; - - // ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76 - struct - { - uint32 unused; // 3 - uint64 duelCount; // 4 - } win_duel; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96 - struct - { - uint32 powerType; // 3 mana=0, 1=rage, 3=energy, 6=runic power - } highest_power; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97 - struct - { - uint32 statType; // 3 4=spirit, 3=int, 2=stamina, 1=agi, 0=strength - } highest_stat; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98 - struct - { - uint32 spellSchool; // 3 - } highest_spellpower; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING = 100 - struct - { - uint32 ratingType; // 3 - } highest_rating; - - // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109 - struct - { - uint32 lootType; // 3 3=fishing, 2=pickpocket, 4=disentchant - uint64 lootTypeCount; // 4 - } loot_type; - - // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112 - struct - { - uint32 skillLine; // 3 - uint64 spellCount; // 4 - } learn_skill_line; - - // ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113 - struct - { - uint32 unused; // 3 - uint64 killCount; // 4 - } honorable_kill; - - struct - { - uint32 unused; - uint64 dungeonsComplete; - } use_lfg; - - struct - { - uint32 field3; // 3 main requirement - uint64 count; // 4 main requirement count - } raw; - }; - - struct - { - uint32 additionalRequirement_type; - uint32 additionalRequirement_value; - } additionalRequirements[MAX_CRITERIA_REQUIREMENTS]; - - char* name; // 9 m_description_lang - uint32 completionFlag; // 10 m_flags - uint32 timedCriteriaStartType; // 11 m_timer_start_event Only appears with timed achievements, seems to be the type of starting a timed Achievement, only type 1 and some of type 6 need manual starting - // 1: ByEventId(?) (serverside IDs), 2: ByQuestId, 5: ByCastSpellId(?) - // 6: BySpellIdTarget(some of these are unknown spells, some not, some maybe spells) - // 7: ByKillNpcId, 9: ByUseItemId - uint32 timedCriteriaMiscId; // 12 m_timer_asset_id Alway appears with timed events, used internally to start the achievement, store - uint32 timeLimit; // 13 m_timer_time time limit in seconds - uint32 showOrder; // 14 m_ui_order also used in achievement shift-links as index in state bitmask - //uint32 unk1; // 15 only one value, still unknown - //uint32 unk2; // 16 all zeros - uint32 additionalConditionType[MAX_ADDITIONAL_CRITERIA_CONDITIONS]; // 17-19 - uint32 additionalConditionValue[MAX_ADDITIONAL_CRITERIA_CONDITIONS]; // 20-22 -}; - // Temporary define until max depth is found somewhere (adt?) #define MAX_MAP_DEPTH -5000 @@ -897,6 +429,134 @@ struct CreatureTypeEntry //uint32 Flags; // 2 no exp? critters, non-combat pets, gas cloud. }; +struct CriteriaEntry +{ + uint32 ID; // 0 + uint32 Type; // 1 + union + { + uint32 ID; + // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0 + // ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20 + uint32 CreatureID; + + // ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1 + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15 + // ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16 + // ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32 + // ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33 + uint32 MapID; + + // ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7 + // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40 + // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75 + // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112 + uint32 SkillID; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8 + uint32 AchievementID; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11 + uint32 ZoneID; + + // ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12 + uint32 CurrencyID; + + // ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18 + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19 + uint32 GroupSize; + + // ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26 + uint32 DamageType; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27 + uint32 QuestID; + + // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28 + // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69 + // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29 + // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110 + // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34 + uint32 SpellID; + + // ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE + uint32 ObjectiveId; + + // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31 + uint32 AreaID; + + // ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36 + // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41 + // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42 + // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57 + uint32 ItemID; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38 + // ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING = 39 + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39 + uint32 TeamType; + + // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43 + uint32 WorldMapOverlayID; + + // ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46 + uint32 FactionID; + + // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49 + uint32 ItemSlot; + + // ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50 + // ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51 + uint32 RollValue; + + // ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52 + uint32 ClassID; + + // ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53 + uint32 RaceID; + + // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54 + uint32 EmoteID; + + // ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68 + // ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72 + uint32 GameObjectID; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96 + uint32 PowerType; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97 + uint32 StatType; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98 + uint32 SpellSchool; + + // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109 + uint32 LootType; + } Asset; // 2 + uint32 StartEvent; // 3 + uint32 StartAsset; // 4 + uint32 StartTimer; // 5 + uint32 FailEvent; // 6 + uint32 FailAsset; // 7 + uint32 ModifierTreeId; // 8 + //uint32 Flags; // 9 + uint32 EligibilityWorldStateID; // 10 + uint32 EligibilityWorldStateValue; // 11 +}; + +struct CriteriaTreeEntry +{ + uint32 ID; // 0 + uint32 CriteriaID; // 1 + uint64 Amount; // 2 + uint32 Operator; // 3 + uint32 Parent; // 4 + //uint32 Flags; // 5 + //char* DescriptionLang; // 6 + //uint32 OrderIndex; // 7 +}; + /* not used struct CurrencyCategoryEntry { @@ -1567,6 +1227,16 @@ struct MinorTalentEntry uint32 OrderIndex; // 3 }; +struct ModifierTreeEntry +{ + uint32 ID; // 0 + uint32 Type; // 1 + uint32 Asset[2]; // 2-3 + uint32 Operator; // 4 + uint32 Amount; // 5 + uint32 Parent; // 6 +}; + struct MountCapabilityEntry { uint32 ID; // 0 diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 852af09fdb2..bbba02b5ea5 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -20,12 +20,11 @@ #define TRINITY_DBCSFRM_H // x - skip, X - skip, s - char*, f - float, i - uint32, b - uint8, d - index (not included) -// n - index (included), l - bool, p - field present in sql dbc, a - field absent in sql dbc +// n - index (included), l - uint64, p - field present in sql dbc, a - field absent in sql dbc -char const Achievementfmt[] = "niixsxiixixxiix"; +char const Achievementfmt[] = "niixsxiixixxiii"; const std::string CustomAchievementfmt = "pppaaaapapaapp"; const std::string CustomAchievementIndex = "ID"; -char const AchievementCriteriafmt[] = "niiiliiiisiiiiixxiiiiii"; char const AreaTableEntryfmt[] = "iiiniixxxxsxixiiiiixxxxxxxxxx"; char const AreaGroupEntryfmt[] = "niiiiiii"; char const AreaTriggerEntryfmt[] = "nifffxxxfffffxxxx"; @@ -49,6 +48,8 @@ char const CreatureFamilyfmt[] = "nfifiiiiixsx"; char const CreatureModelDatafmt[] = "nixxxxxxxxxxxxxffxxxxxxxxxxxxxxxxx"; char const CreatureSpellDatafmt[] = "niiiixxxx"; char const CreatureTypefmt[] = "nxx"; +char const Criteriafmt[] = "niiiiiiiixii"; +char const CriteriaTreefmt[] = "niliixxx"; char const CurrencyTypesfmt[] = "nixxxxxiiixx"; char const DestructibleModelDatafmt[] = "nixxxixxxxixxxxixxxxxxxx"; char const DungeonEncounterfmt[] = "niiixsxxx"; @@ -108,6 +109,7 @@ char const MapEntryfmt[] = "nxiixxsixxixiffxiiiixx"; char const MapDifficultyEntryfmt[] = "diisiixx"; char const MinorTalentEntryfmt[] = "niii"; char const MovieEntryfmt[] = "nxxxx"; +char const ModifierTreefmt[] = "niiiiii"; char const MountCapabilityfmt[] = "niiiiiii"; char const MountTypefmt[] = "niiiiiiiiiiiiiiiiiiiiiiii"; char const NameGenfmt[] = "dsii"; diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 0bfa08d62c9..bd9b05e35bc 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -1550,17 +1550,19 @@ void Guild::HandleSetAchievementTracking(WorldSession* session, std::set { std::set criteriaIds; + /* for (std::set::iterator achievementId = achievementIds.begin(); achievementId != achievementIds.end(); ++achievementId) { if (AchievementCriteriaEntryList const* cList = sAchievementMgr->GetAchievementCriteriaByAchievement(*achievementId)) { for (AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr) { - AchievementCriteriaEntry const* criteria = *itr; + AchievementCriteriaTree const* criteria = *itr; criteriaIds.insert(criteria->ID); } } } + */ member->SetTrackedCriteriaIds(criteriaIds); m_achievementMgr.SendAllTrackedCriterias(player, member->GetTrackedCriteriaIds()); @@ -2629,7 +2631,7 @@ void Guild::BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const player->GetSession()->SendPacket(packet); } -void Guild::BroadcastPacket(WorldPacket* packet) const +void Guild::BroadcastPacket(WorldPacket const* packet) const { for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindPlayer()) diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 4abeb282b0c..132ecc72f89 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -846,7 +846,7 @@ public: void BroadcastToGuild(WorldSession* session, bool officerOnly, std::string const& msg, uint32 language = LANG_UNIVERSAL) const; void BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std::string const& msg, std::string const& prefix) const; void BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const; - void BroadcastPacket(WorldPacket* packet) const; + void BroadcastPacket(WorldPacket const* packet) const; void BroadcastPacketIfTrackingAchievement(WorldPacket* packet, uint32 criteriaId) const; void MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, uint32 minRank); diff --git a/src/server/game/Server/Packets/AchievementPackets.cpp b/src/server/game/Server/Packets/AchievementPackets.cpp new file mode 100644 index 00000000000..d471d87426c --- /dev/null +++ b/src/server/game/Server/Packets/AchievementPackets.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "AchievementPackets.h" + +WorldPacket const* WorldPackets::Achievement::AllAchievements::Write() +{ + _worldPacket << uint32(Earned.size()); + _worldPacket << uint32(Progress.size()); + + for (EarnedAchievement const& earned : Earned) + { + _worldPacket << uint32(earned.Id); + _worldPacket.AppendPackedTime(earned.Date); + _worldPacket << earned.Owner; + _worldPacket << uint32(earned.VirtualRealmAddress); + _worldPacket << uint32(earned.NativeRealmAddress); + } + + for (CriteriaProgress const& progress : Progress) + { + _worldPacket << uint32(progress.Id); + _worldPacket << uint64(progress.Quantity); + _worldPacket << progress.Player; + _worldPacket.AppendPackedTime(progress.Date); + _worldPacket << uint32(progress.TimeFromStart); + _worldPacket << uint32(progress.TimeFromCreate); + _worldPacket.WriteBits(progress.Flags, 4); + _worldPacket.FlushBits(); + } + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Achievement::CriteriaUpdate::Write() +{ + _worldPacket << uint32(CriteriaID); + _worldPacket << uint64(Quantity); + _worldPacket << PlayerGUID; + _worldPacket << uint32(Flags); + _worldPacket.AppendPackedTime(CurrentTime); + _worldPacket << uint32(ElapsedTime); + _worldPacket << uint32(CreationTime); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Achievement::AchievementEarned::Write() +{ + _worldPacket << Sender; + _worldPacket << Earner; + _worldPacket << uint32(AchievementID); + _worldPacket.AppendPackedTime(Time); + _worldPacket << uint32(EarnerNativeRealm); + _worldPacket << uint32(EarnerVirtualRealm); + _worldPacket.WriteBit(Initial); + _worldPacket.FlushBits(); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/AchievementPackets.h b/src/server/game/Server/Packets/AchievementPackets.h new file mode 100644 index 00000000000..9d609372831 --- /dev/null +++ b/src/server/game/Server/Packets/AchievementPackets.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef game_AchievementPackets_h__ +#define game_AchievementPackets_h__ + +#include "ObjectGuid.h" +#include "Packet.h" + +namespace WorldPackets +{ + namespace Achievement + { + struct EarnedAchievement + { + uint32 Id = 0; + time_t Date = time_t(0); + ObjectGuid Owner; + uint32 VirtualRealmAddress = 0; + uint32 NativeRealmAddress = 0; + }; + + struct CriteriaProgress + { + uint32 Id = 0; + uint64 Quantity = 0; + ObjectGuid Player; + uint32 Flags = 0; + time_t Date = time_t(0); + uint32 TimeFromStart = 0; + uint32 TimeFromCreate = 0; + }; + + class AllAchievements final : public ServerPacket + { + public: + AllAchievements() : ServerPacket(SMSG_ALL_ACHIEVEMENT_DATA) { } + + WorldPacket const* Write() override; + + std::vector Earned; + std::vector Progress; + }; + + class CriteriaUpdate final : public ServerPacket + { + public: + CriteriaUpdate() : ServerPacket(SMSG_CRITERIA_UPDATE, 4 + 8 + 16 + 4 + 4 + 4 + 4) { } + + WorldPacket const* Write() override; + + uint32 CriteriaID = 0; + uint64 Quantity = 0; + ObjectGuid PlayerGUID; + uint32 Flags = 0; + time_t CurrentTime = time_t(0); + uint32 ElapsedTime = 0; + uint32 CreationTime = 0; + }; + + class AchievementEarned final : public ServerPacket + { + public: + AchievementEarned() : ServerPacket(SMSG_ACHIEVEMENT_EARNED, 16 + 4 + 4 + 4 + 4 + 1 + 16) { } + + WorldPacket const* Write() override; + + ObjectGuid Earner; + uint32 EarnerNativeRealm = 0; + uint32 EarnerVirtualRealm = 0; + uint32 AchievementID = 0; + time_t Time = time_t(0); + bool Initial = false; + ObjectGuid Sender; + }; + } +} + +#endif // game_AchievementPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index e18e5e984ac..603e55ff738 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -709,14 +709,14 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_RESTRICTED_WARNING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_TOYS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTION_BUTTONS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVATETAXIREPLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADDON_INFO, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_RUNE_POWER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADJUST_SPLINE_DURATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AI_REACTION, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_SPIRIT_HEALER_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MOVEMENT_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -867,7 +867,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_RECLAIM_DELAY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CREATURE_QUERY_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CROSSED_INEBRIATION_THRESHOLD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_RESTORED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 68fd9c30d48..ddad78a527b 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -686,16 +686,16 @@ enum OpcodeServer : uint32 SMSG_ACCOUNT_RESTRICTED_WARNING = 0xBADD, SMSG_ACCOUNT_TOYS_UPDATE = 0x0590, SMSG_ACHIEVEMENT_DELETED = 0xBADD, - SMSG_ACHIEVEMENT_EARNED = 0xBADD, + SMSG_ACHIEVEMENT_EARNED = 0x010E, SMSG_ACTION_BUTTONS = 0x1D1F, SMSG_ACTIVATETAXIREPLY = 0xBADD, SMSG_ADDON_INFO = 0x1D9F, SMSG_ADD_RUNE_POWER = 0xBADD, SMSG_ADJUST_SPLINE_DURATION = 0x0104, SMSG_AI_REACTION = 0x0BA1, - SMSG_ALL_ACHIEVEMENT_DATA = 0xBADD, - SMSG_ALL_ACHIEVEMENT_DATA_ACCOUNT = 0x0123, - SMSG_ALL_ACHIEVEMENT_DATA_PLAYER = 0x0030, + SMSG_ACCOUNT_CRITERIA_UPDATE = 0x0912, + SMSG_ALL_ACCOUNT_CRITERIA = 0x0123, + SMSG_ALL_ACHIEVEMENT_DATA = 0x0030, SMSG_AREA_SPIRIT_HEALER_TIME = 0xBADD, SMSG_AREA_TRIGGER_MESSAGE = 0xBADD, SMSG_AREA_TRIGGER_MOVEMENT_UPDATE = 0xBADD, @@ -852,9 +852,7 @@ enum OpcodeServer : uint32 SMSG_CORPSE_RECLAIM_DELAY = 0x0BE2, SMSG_CREATURE_QUERY_RESPONSE = 0x0A26, SMSG_CRITERIA_DELETED = 0xBADD, - SMSG_CRITERIA_UPDATE = 0xBADD, - SMSG_CRITERIA_UPDATE_ACCOUNT = 0x0912, - SMSG_CRITERIA_UPDATE_PLAYER = 0x1904, + SMSG_CRITERIA_UPDATE = 0x1904, SMSG_CROSSED_INEBRIATION_THRESHOLD = 0xBADD, SMSG_CURRENCY_LOOT_REMOVED = 0xBADD, SMSG_CURRENCY_LOOT_RESTORED = 0xBADD, diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 5c8706da09c..7195c58ae00 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1693,6 +1693,8 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Achievements..."); sAchievementMgr->LoadAchievementReferenceList(); + TC_LOG_INFO("server.loading", "Loading Achievement Criteria Modifier trees..."); + sAchievementMgr->LoadAchievementCriteriaModifiersTree(); TC_LOG_INFO("server.loading", "Loading Achievement Criteria Lists..."); sAchievementMgr->LoadAchievementCriteriaList(); TC_LOG_INFO("server.loading", "Loading Achievement Criteria Data..."); -- cgit v1.2.3 From d51b2c04c8b9e7d9f3179055f75d6873bee73732 Mon Sep 17 00:00:00 2001 From: Gigi1237 Date: Sun, 28 Dec 2014 15:30:32 +0000 Subject: Core/Scripts: Add Conjure Refreshment Table script - Fix Conjure Refreshment for characters above level 85 Closes #13780 --- sql/updates/world/2014_12_28_01_world.sql | 3 ++ src/server/scripts/Spells/spell_mage.cpp | 69 +++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 sql/updates/world/2014_12_28_01_world.sql (limited to 'src') diff --git a/sql/updates/world/2014_12_28_01_world.sql b/sql/updates/world/2014_12_28_01_world.sql new file mode 100644 index 00000000000..c571069edca --- /dev/null +++ b/sql/updates/world/2014_12_28_01_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `spell_id`=43987; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(43987, 'spell_mage_conjure_refreshment_table'); diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index baf7ff48cb5..fc8ba0ffad0 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -392,7 +392,7 @@ class spell_mage_cone_of_cold : public SpellScriptLoader }; // 42955 Conjure Refreshment -/// Updated 4.3.4 +/// Updated 6.0.3 struct ConjureRefreshmentData { uint32 minLevel; @@ -400,7 +400,7 @@ struct ConjureRefreshmentData uint32 spellId; }; -uint8 const MAX_CONJURE_REFRESHMENT_SPELLS = 7; +uint8 const MAX_CONJURE_REFRESHMENT_SPELLS = 9; ConjureRefreshmentData const _conjureData[MAX_CONJURE_REFRESHMENT_SPELLS] = { { 33, 43, 92739 }, @@ -409,7 +409,9 @@ ConjureRefreshmentData const _conjureData[MAX_CONJURE_REFRESHMENT_SPELLS] = { 64, 73, 92805 }, { 74, 79, 74625 }, { 80, 84, 92822 }, - { 85, 85, 92727 } + { 85, 89, 92727 }, + { 90, 99, 116130 }, + { 100, 100, 167143 } }; // 42955 - Conjure Refreshment @@ -462,6 +464,66 @@ class spell_mage_conjure_refreshment : public SpellScriptLoader } }; +uint8 const MAX_CONJURE_REFRESHMENT_TABLE_SPELLS = 5; +ConjureRefreshmentData const _conjureTableData[MAX_CONJURE_REFRESHMENT_TABLE_SPELLS] = +{ + { 73, 79, 120056 }, + { 80, 84, 120055 }, + { 85, 89, 120054 }, + { 90, 99, 120053 }, + { 100, 100, 167145 } +}; + +// 43987 - Conjure Refreshment Table +class spell_mage_conjure_refreshment_table : public SpellScriptLoader +{ +public: + spell_mage_conjure_refreshment_table() : SpellScriptLoader("spell_mage_conjure_refreshment_table") { } + + class spell_mage_conjure_refreshment_table_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mage_conjure_refreshment_table_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + for (uint8 i = 0; i < MAX_CONJURE_REFRESHMENT_TABLE_SPELLS; ++i) + if (!sSpellMgr->GetSpellInfo(_conjureTableData[i].spellId)) + return false; + return true; + } + + bool Load() override + { + if (GetCaster()->GetTypeId() != TYPEID_PLAYER) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + uint8 level = GetHitUnit()->getLevel(); + for (uint8 i = 0; i < MAX_CONJURE_REFRESHMENT_TABLE_SPELLS; ++i) + { + ConjureRefreshmentData const& spellData = _conjureTableData[i]; + if (level < spellData.minLevel || level > spellData.maxLevel) + continue; + GetHitUnit()->CastSpell(GetHitUnit(), spellData.spellId); + break; + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mage_conjure_refreshment_table_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mage_conjure_refreshment_table_SpellScript(); + } +}; + // 543 - Fire War class spell_mage_fire_frost_ward : public SpellScriptLoader { @@ -1468,6 +1530,7 @@ void AddSC_mage_spell_scripts() new spell_mage_cold_snap(); new spell_mage_cone_of_cold(); new spell_mage_conjure_refreshment(); + new spell_mage_conjure_refreshment_table(); new spell_mage_fire_frost_ward(); new spell_mage_focus_magic(); new spell_mage_frostbolt(); -- cgit v1.2.3 From 3cdc66bec68e9dd9bf792f4b37328d4fd67bc266 Mon Sep 17 00:00:00 2001 From: jackpoz Date: Sat, 27 Dec 2014 00:10:01 +0100 Subject: Shared/Networking: Fix buffer overflow in Socket handling Fix a buffer overflow caused by Boost trying to store too much data in a buffer too small. (cherry picked from commit cdf6c884624be33b5782bcca0e206e5c291a517b) --- src/server/shared/Networking/MessageBuffer.h | 8 ++++++++ src/server/shared/Networking/Socket.h | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h index 2dcd4fbc161..a214af9d127 100644 --- a/src/server/shared/Networking/MessageBuffer.h +++ b/src/server/shared/Networking/MessageBuffer.h @@ -81,6 +81,14 @@ public: } } + // Ensures there's "some" free space, make sure to call Normalize() before this + void EnsureFreeSpace() + { + // Double the size of the buffer if it's already full + if (GetRemainingSpace() == 0) + _storage.resize(_storage.size() * 2); + } + void Write(void const* data, std::size_t size) { if (size) diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h index 5c891d925fa..6c367e5649d 100644 --- a/src/server/shared/Networking/Socket.h +++ b/src/server/shared/Networking/Socket.h @@ -92,7 +92,8 @@ public: return; _readBuffer.Normalize(); - _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), READ_BLOCK_SIZE), + _readBuffer.EnsureFreeSpace(); + _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), _readBuffer.GetRemainingSpace()), std::bind(&Socket::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } -- cgit v1.2.3 From 62b2ccca13e3e00ca68b4299d0e980b884ddf07d Mon Sep 17 00:00:00 2001 From: Heihachi Date: Tue, 11 Nov 2014 14:56:26 -0600 Subject: Core/Player: Fix Restes/RaF exp on the exp bar and from kills Final Time :'( (cherry picked from commit 2d000a42e9a8dbc1f16450143835221d7a7c149a) --- src/server/game/Entities/Player/Player.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9129aca8078..904600a2481 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -20853,12 +20853,15 @@ void Player::SetRestBonus(float rest_bonus_new) m_rest_bonus = rest_bonus_new; // update data for client - if (GetSession()->IsARecruiter() || (GetSession()->GetRecruiterId() != 0)) + if ((GetsRecruitAFriendBonus(true) && (GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0))) SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RAF_LINKED); - else if (m_rest_bonus > 10) - SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RESTED); // Set Reststate = Rested - else if (m_rest_bonus <= 1) - SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NOT_RAF_LINKED); // Set Reststate = Normal + else + { + if (m_rest_bonus > 10) + SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RESTED); + else if (m_rest_bonus <= 1) + SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NOT_RAF_LINKED); + } //RestTickUpdate SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus)); -- cgit v1.2.3 From 8fec200670e89003773b9bea4e0e90b3b5c3028c Mon Sep 17 00:00:00 2001 From: Golrag Date: Sun, 28 Dec 2014 16:01:53 +0000 Subject: Core/Opcodes: Added Structure for: * CMSG_GAMEOBJECT_QUERY * CMSG_GAMEOBJ_REPORT_USE * CMSG_GAMEOBJ_USE * SMSG_GAMEOBJECT_QUERY_RESPONSE Closes #13791 --- src/server/game/Handlers/QueryHandler.cpp | 77 ++++++++-------------- src/server/game/Handlers/SpellHandler.cpp | 22 ++----- .../game/Server/Packets/GameObjectPackets.cpp | 28 ++++++++ src/server/game/Server/Packets/GameObjectPackets.h | 51 ++++++++++++++ src/server/game/Server/Packets/QueryPackets.cpp | 41 ++++++++++++ src/server/game/Server/Packets/QueryPackets.h | 36 ++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 11 ++-- src/server/game/Server/WorldSession.h | 13 +++- 8 files changed, 205 insertions(+), 74 deletions(-) create mode 100644 src/server/game/Server/Packets/GameObjectPackets.cpp create mode 100644 src/server/game/Server/Packets/GameObjectPackets.h (limited to 'src') diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index 4beddd757da..6cd8acf08dd 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -132,60 +132,39 @@ void WorldSession::HandleCreatureQuery(WorldPackets::Query::QueryCreature& packe } /// Only _static_ data is sent in this packet !!! -void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recvData) +void WorldSession::HandleGameObjectQueryOpcode(WorldPackets::Query::QueryGameObject& packet) { - uint32 entry; - recvData >> entry; - ObjectGuid guid; - recvData >> guid; + WorldPackets::Query::QueryGameObjectResponse response; + GameObjectTemplate const* gameObjectInfo = sObjectMgr->GetGameObjectTemplate(packet.Entry); - const GameObjectTemplate* info = sObjectMgr->GetGameObjectTemplate(entry); - if (info) - { - std::string Name; - std::string IconName; - std::string CastBarCaption; - - Name = info->name; - IconName = info->IconName; - CastBarCaption = info->castBarCaption; + response.Entry = packet.Entry; - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - if (GameObjectLocale const* gl = sObjectMgr->GetGameObjectLocale(entry)) - { - ObjectMgr::GetLocaleString(gl->Name, loc_idx, Name); - ObjectMgr::GetLocaleString(gl->CastBarCaption, loc_idx, CastBarCaption); - } - } - TC_LOG_DEBUG("network", "WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name.c_str(), entry); - WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 150); - data << uint32(entry); - data << uint32(info->type); - data << uint32(info->displayId); - data << Name; - data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4 - data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword) - data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting") - data << info->unk1; // 2.0.3, string - data.append(info->raw.data, MAX_GAMEOBJECT_DATA); - data << float(info->size); // go size - for (uint32 i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i) - data << uint32(info->questItems[i]); // itemId[6], quest drop - data << int32(info->unkInt32); // 4.x, unknown - SendPacket(&data); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); - } - else + if (gameObjectInfo) { - TC_LOG_DEBUG("network", "WORLD: CMSG_GAMEOBJECT_QUERY - Missing gameobject info for (%s, ENTRY: %u)", - guid.ToString().c_str(), entry); - WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 4); - data << uint32(entry | 0x80000000); - SendPacket(&data); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); + response.Allow = true; + WorldPackets::Query::GameObjectStats& stats = response.Stats; + + stats.CastBarCaption = gameObjectInfo->castBarCaption; + stats.DisplayID = gameObjectInfo->displayId; + stats.IconName = gameObjectInfo->IconName; + stats.Name[0] = gameObjectInfo->name; + + for (uint8 i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; i++) + if (gameObjectInfo->questItems[i]) + stats.QuestItems.push_back(gameObjectInfo->questItems[i]); + for (uint32 i = 0; i < MAX_GAMEOBJECT_DATA; i++) + stats.Data[i] = gameObjectInfo->raw.data[i]; + + stats.Size = gameObjectInfo->size; + stats.Type = gameObjectInfo->type; + stats.UnkString = gameObjectInfo->unk1; + stats.UnkInt32 = gameObjectInfo->unkInt32; + stats.Expansion = 0; } + else + response.Allow = false; + + SendPacket(response.Write()); } void WorldSession::HandleCorpseQueryOpcode(WorldPacket& /*recvData*/) diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 0b468ca0b47..64373e4b674 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -36,6 +36,7 @@ #include "Player.h" #include "Config.h" #include "SpellPackets.h" +#include "GameObjectPackets.h" void WorldSession::HandleClientCastFlags(WorldPacket& recvPacket, uint8 castFlags, SpellCastTargets& targets) { @@ -284,14 +285,9 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) pUser->SendLoot(item->GetGUID(), LOOT_CORPSE); } -void WorldSession::HandleGameObjectUseOpcode(WorldPacket& recvData) +void WorldSession::HandleGameObjectUseOpcode(WorldPackets::GameObject::GameObjectUse& packet) { - ObjectGuid guid; - recvData >> guid; - - TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_GAMEOBJ_USE Message [%s]", guid.ToString().c_str()); - - if (GameObject* obj = GetPlayer()->GetMap()->GetGameObject(guid)) + if (GameObject* obj = GetPlayer()->GetMap()->GetGameObject(packet.Guid)) { if (!obj->IsWithinDistInMap(GetPlayer(), obj->GetInteractionDistance())) return; @@ -305,18 +301,13 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPacket& recvData) } } -void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) +void WorldSession::HandleGameobjectReportUse(WorldPackets::GameObject::GameObjectReportUse& packet) { - ObjectGuid guid; - recvPacket >> guid; - - TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_GAMEOBJ_REPORT_USE Message [%s]", guid.ToString().c_str()); - // ignore for remote control state if (_player->m_mover != _player) return; - GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); + GameObject* go = GetPlayer()->GetMap()->GetGameObject(packet.Guid); if (!go) return; @@ -331,9 +322,6 @@ void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest) { - - TC_LOG_DEBUG("network", "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u", castRequest.CastID, castRequest.SpellID, castRequest.SendCastFlags); - // ignore for remote control state (for player case) Unit* mover = _player->m_mover; if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) diff --git a/src/server/game/Server/Packets/GameObjectPackets.cpp b/src/server/game/Server/Packets/GameObjectPackets.cpp new file mode 100644 index 00000000000..21e8305eb5e --- /dev/null +++ b/src/server/game/Server/Packets/GameObjectPackets.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "GameObjectPackets.h" + +void WorldPackets::GameObject::GameObjectUse::Read() +{ + _worldPacket >> Guid; +} + +void WorldPackets::GameObject::GameObjectReportUse::Read() +{ + _worldPacket >> Guid; +} diff --git a/src/server/game/Server/Packets/GameObjectPackets.h b/src/server/game/Server/Packets/GameObjectPackets.h new file mode 100644 index 00000000000..76b3478844b --- /dev/null +++ b/src/server/game/Server/Packets/GameObjectPackets.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef GOPackets_h__ +#define GOPackets_h__ + +#include "Packet.h" +#include "DB2Stores.h" +#include "GameObject.h" +#include "WorldSession.h" + +namespace WorldPackets +{ + namespace GameObject + { + class GameObjectUse final : public ClientPacket + { + public: + GameObjectUse(WorldPacket&& packet) : ClientPacket(CMSG_GAMEOBJ_USE, std::move(packet)) { } + + void Read() override; + + ObjectGuid Guid; + }; + + class GameObjectReportUse final : public ClientPacket + { + public: + GameObjectReportUse(WorldPacket&& packet) : ClientPacket(CMSG_GAMEOBJ_REPORT_USE, std::move(packet)) { } + + void Read() override; + + ObjectGuid Guid; + }; + } +} +#endif // GOPackets_h__ diff --git a/src/server/game/Server/Packets/QueryPackets.cpp b/src/server/game/Server/Packets/QueryPackets.cpp index f100013d7a4..84792b3c21e 100644 --- a/src/server/game/Server/Packets/QueryPackets.cpp +++ b/src/server/game/Server/Packets/QueryPackets.cpp @@ -221,3 +221,44 @@ WorldPacket const* WorldPackets::Query::HotfixNotifyBlob::Write() return &_worldPacket; } + +void WorldPackets::Query::QueryGameObject::Read() +{ + _worldPacket >> Entry; + _worldPacket >> Guid; +} + +WorldPacket const* WorldPackets::Query::QueryGameObjectResponse::Write() +{ + _worldPacket << Entry; + _worldPacket.WriteBit(Allow); + + if (Allow) + { + _worldPacket << Stats.UnkInt32; + if (Stats.UnkInt32 == 0) + return &_worldPacket; + + _worldPacket << Stats.Type; + _worldPacket << Stats.DisplayID; + for (int8 i = 0; i < 4; i++) + _worldPacket << Stats.Name[i]; + + _worldPacket << Stats.IconName; + _worldPacket << Stats.CastBarCaption; + _worldPacket << Stats.UnkString; + + for (uint32 i = 0; i < MAX_GAMEOBJECT_DATA; i++) + _worldPacket << Stats.Data[i]; + + _worldPacket << Stats.Size; + + _worldPacket << uint8(Stats.QuestItems.size()); + for (int32 questItem : Stats.QuestItems) + _worldPacket << questItem; + + _worldPacket << Stats.Expansion; + } + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/QueryPackets.h b/src/server/game/Server/Packets/QueryPackets.h index 4581c20c6e5..749ff1343a2 100644 --- a/src/server/game/Server/Packets/QueryPackets.h +++ b/src/server/game/Server/Packets/QueryPackets.h @@ -210,6 +210,42 @@ namespace WorldPackets HotfixData const* Hotfixes = nullptr; }; + + class QueryGameObject final : public ClientPacket + { + public: + QueryGameObject(WorldPacket&& packet) : ClientPacket(CMSG_GAMEOBJECT_QUERY, std::move(packet)) { } + + void Read() override; + uint32 Entry = 0; + ObjectGuid Guid; + }; + + struct GameObjectStats + { + std::string Name[4]; + std::string IconName; + std::string CastBarCaption; + std::string UnkString; + int32 UnkInt32 = 0; + uint32 Type = 0; + uint32 DisplayID = 0; + uint32 Data[MAX_GAMEOBJECT_DATA]; + float Size = 0.0f; + std::vector QuestItems; + uint32 Expansion = 0; + }; + + class QueryGameObjectResponse final : public ServerPacket + { + public: + QueryGameObjectResponse() : ServerPacket(SMSG_GAMEOBJECT_QUERY_RESPONSE, 165) { } // Guess size + + WorldPacket const* Write() override; + uint32 Entry = 0; + bool Allow = false; + GameObjectStats Stats; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 603e55ff738..1cca6672086 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -33,6 +33,7 @@ #include "Packets/TalentPackets.h" #include "Packets/TradePackets.h" #include "Packets/ItemPackets.h" +#include "Packets/GameObjectPackets.h" template class PacketHandler : public ClientOpcodeHandler @@ -299,10 +300,10 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_FAR_SIGHT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleFarSightOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_FORCE_MOVE_ROOT_ACK, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMoveRootAck ); DEFINE_OPCODE_HANDLER_OLD(CMSG_FORCE_MOVE_UNROOT_ACK, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMoveUnRootAck ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GAMEOBJECT_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGameObjectQueryOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GAMEOBJ_REPORT_USE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGameobjectReportUse ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GAMEOBJ_USE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGameObjectUseOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_MAIL_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGetMailList ); + DEFINE_HANDLER(CMSG_GAMEOBJECT_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Query::QueryGameObject, &WorldSession::HandleGameObjectQueryOpcode); + DEFINE_HANDLER(CMSG_GAMEOBJ_REPORT_USE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::GameObject::GameObjectReportUse, &WorldSession::HandleGameobjectReportUse); + DEFINE_HANDLER(CMSG_GAMEOBJ_USE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::GameObject::GameObjectUse, &WorldSession::HandleGameObjectUseOpcode); + DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_MAIL_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGetMailList); DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_MIRRORIMAGE_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMirrorImageDataRequest ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GMRESPONSE_RESOLVE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMResponseResolve ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GMSURVEY_SUBMIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMSurveySubmit ); @@ -927,7 +928,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_DESPAWN_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_DESPAWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_PAGETEXT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_QUERY_RESPONSE, STATUS_LOGGEDIN, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMEOBJECT_RESET_STATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMESPEED_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAMETIME_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 52f1c76555a..5a4a3465474 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -182,6 +182,7 @@ namespace WorldPackets class QueryPageText; class QueryNPCText; class DBQueryBulk; + class QueryGameObject; } namespace Quest @@ -198,6 +199,12 @@ namespace WorldPackets class AutoEquipItem; class DestroyItem; } + + namespace GameObject + { + class GameObjectReportUse; + class GameObjectUse; + } } enum AccountDataType @@ -694,16 +701,16 @@ class WorldSession void HandleRequestAccountData(WorldPackets::ClientConfig::RequestAccountData& request); void HandleSetActionButtonOpcode(WorldPackets::Spells::SetActionButton& packet); - void HandleGameObjectUseOpcode(WorldPacket& recPacket); + void HandleGameObjectUseOpcode(WorldPackets::GameObject::GameObjectUse& packet); void HandleMeetingStoneInfo(WorldPacket& recPacket); - void HandleGameobjectReportUse(WorldPacket& recvPacket); + void HandleGameobjectReportUse(WorldPackets::GameObject::GameObjectReportUse& packet); void HandleNameQueryOpcode(WorldPackets::Query::QueryPlayerName& packet); void HandleQueryTimeOpcode(WorldPacket& recvPacket); void HandleCreatureQuery(WorldPackets::Query::QueryCreature& packet); void HandleDBQueryBulk(WorldPackets::Query::DBQueryBulk& packet); - void HandleGameObjectQueryOpcode(WorldPacket& recvPacket); + void HandleGameObjectQueryOpcode(WorldPackets::Query::QueryGameObject& packet); void HandleMoveWorldportAckOpcode(WorldPackets::Movement::WorldPortAck& packet); void HandleMoveWorldportAckOpcode(); // for server-side calls -- cgit v1.2.3 From a26b0f2c76e70f5d695819bb89c4ec605049513d Mon Sep 17 00:00:00 2001 From: Gooyeth Date: Sun, 28 Dec 2014 17:03:33 +0000 Subject: Scripts/Quests: Fix Red Snapper - Very Tasty! GOb Fix 'School of Red Snapper' now disappear correctly when using 'Draenei Fishing Net', the bug is caused because the GameObject is SpellFocus type. Fix #1673 Closes #13748 (cherry picked from commit b0b7a55bdba20aad5b7914c55933daa70afe59ba) --- src/server/game/Spells/SpellMgr.cpp | 3 +++ src/server/scripts/Spells/spell_quest.cpp | 28 +++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 544abc9ca87..0c82730f5a1 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3661,6 +3661,9 @@ void SpellMgr::LoadSpellInfoCorrections() break; // ENDOF ISLE OF CONQUEST SPELLS // + case 29866: // Cast Fishing Net + spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(140); // 6yd + break; default: break; } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index e9cf81f2e64..434a8f75693 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -1076,9 +1076,12 @@ class spell_q14112_14145_chum_the_water: public SpellScriptLoader // http://old01.wowhead.com/quest=9452 - Red Snapper - Very Tasty! enum RedSnapperVeryTasty { - SPELL_CAST_NET = 29866, - ITEM_RED_SNAPPER = 23614, - SPELL_NEW_SUMMON_TEST = 49214, + ITEM_RED_SNAPPER = 23614, + + SPELL_CAST_NET = 29866, + SPELL_NEW_SUMMON_TEST = 49214, + + GO_SCHOOL_OF_RED_SNAPPER = 181616 }; class spell_q9452_cast_net: public SpellScriptLoader @@ -1095,6 +1098,15 @@ class spell_q9452_cast_net: public SpellScriptLoader return GetCaster()->GetTypeId() == TYPEID_PLAYER; } + SpellCastResult CheckCast() + { + GameObject* go = GetCaster()->FindNearestGameObject(GO_SCHOOL_OF_RED_SNAPPER, 3.0f); + if (!go || go->GetRespawnTime()) + return SPELL_FAILED_REQUIRES_SPELL_FOCUS; + + return SPELL_CAST_OK; + } + void HandleDummy(SpellEffIndex /*effIndex*/) { Player* caster = GetCaster()->ToPlayer(); @@ -1104,9 +1116,19 @@ class spell_q9452_cast_net: public SpellScriptLoader caster->CastSpell(caster, SPELL_NEW_SUMMON_TEST, true); } + void HandleActiveObject(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitGObj()->SetRespawnTime(roll_chance_i(50) ? 2 * MINUTE : 3 * MINUTE); + GetHitGObj()->Use(GetCaster()); + GetHitGObj()->SetLootState(GO_JUST_DEACTIVATED); + } + void Register() override { + OnCheckCast += SpellCheckCastFn(spell_q9452_cast_net_SpellScript::CheckCast); OnEffectHit += SpellEffectFn(spell_q9452_cast_net_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnEffectHitTarget += SpellEffectFn(spell_q9452_cast_net_SpellScript::HandleActiveObject, EFFECT_1, SPELL_EFFECT_ACTIVATE_OBJECT); } }; -- cgit v1.2.3 From 611ff7096c5a03b20068e8edcf3db1b0bad6738d Mon Sep 17 00:00:00 2001 From: Nayd Date: Sun, 28 Dec 2014 17:08:32 +0000 Subject: Core/Spells: Remove a not-required spell dbc correction (b0b7a55bdba20aad5b7914c55933daa70afe59ba) (cherry picked from commit 81a0e68c9f506c909771454cb92d246f5997384d) --- src/server/game/Spells/SpellMgr.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 0c82730f5a1..544abc9ca87 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3661,9 +3661,6 @@ void SpellMgr::LoadSpellInfoCorrections() break; // ENDOF ISLE OF CONQUEST SPELLS // - case 29866: // Cast Fishing Net - spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(140); // 6yd - break; default: break; } -- cgit v1.2.3 From 76fa042fdc82a92780c148839f33ff8fbb099ab6 Mon Sep 17 00:00:00 2001 From: Mihapro Date: Sun, 28 Dec 2014 18:00:13 +0000 Subject: Scripts/Instance: The Stonecore updates Stonecore Teleporters scripted. Some corrections, better handlings, fixed Travis warnings ... Closes #13626 (cherry picked from commit 9a941ae125c8b22b802270f7f419c1a8bfd2a343) Conflicts: src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp src/server/scripts/Maelstrom/Stonecore/stonecore.cpp --- sql/updates/world/2014_12_28_02_world.sql | 25 ++++ src/server/game/Spells/SpellMgr.cpp | 5 + .../scripts/Maelstrom/Stonecore/boss_corborus.cpp | 26 ++-- .../Stonecore/boss_high_priestess_azil.cpp | 154 +++++---------------- .../scripts/Maelstrom/Stonecore/boss_ozruk.cpp | 39 ++---- .../scripts/Maelstrom/Stonecore/boss_slabhide.cpp | 39 ++---- .../Maelstrom/Stonecore/instance_stonecore.cpp | 95 +++++-------- .../scripts/Maelstrom/Stonecore/stonecore.cpp | 53 +++---- src/server/scripts/Maelstrom/Stonecore/stonecore.h | 5 + 9 files changed, 170 insertions(+), 271 deletions(-) create mode 100644 sql/updates/world/2014_12_28_02_world.sql (limited to 'src') diff --git a/sql/updates/world/2014_12_28_02_world.sql b/sql/updates/world/2014_12_28_02_world.sql new file mode 100644 index 00000000000..9bbd10e71b6 --- /dev/null +++ b/sql/updates/world/2014_12_28_02_world.sql @@ -0,0 +1,25 @@ +-- The Stonecore updates +-- Spell conditions +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` IN (93167, 86862, 86863); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 1, 93167, 0, 0, 31, 0, 3, 40350, 0, 0, 0, 0, '', 'Twilight Documents targets Generic Trigger LAB'), +(13, 1, 86862, 0, 0, 31, 0, 3, 42355, 0, 0, 0, 0, '', 'Seismic Shard targets Seismic Shards'), +(13, 1, 86862, 0, 0, 1, 0, 79009, 0, 0, 0, 0, 0, '', 'Seismic Shard''s target must have SPELL_SEISMIC_SHARD_VISUAL aura'), +(13, 1, 86863, 0, 0, 31, 0, 3, 42333, 0, 0, 0, 0, '', 'Seismic Shard targets High Priestess Azil'); + +-- Set CREATURE_FLAG_EXTRA_TRIGGER to Stonecore Teleporters, Lava Fissure, Stalactite Trigger - Boss, Rupture Controller, Rupture, Gravity Well, Seismic Shard +UPDATE `creature_template` SET `flags_extra` = 128 WHERE `entry` IN (51396, 51397, 43242, 43159, 49597, 49576, 42499, 42355); + +-- Stonecore Teleporters +DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN (51396, 51397); +INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES +(51396, 95284, 3, 0), +(51397, 95285, 3, 0); + +DELETE FROM `spell_target_position` WHERE `id` IN (95284, 95285); +INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `VerifiedBuild`) VALUES +(95284, 0, 725, 1313.26, 1236.833, 247.2859, 0), +(95285, 0, 725, 853.8577, 999.7518, 317.3986, 0); + +-- Remove cpp script from Seismic Shard (86862) spell +DELETE FROM `spell_script_names` WHERE `spell_id` = 86862; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 544abc9ca87..46ec7553d02 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3618,6 +3618,11 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->ManaCost = 0; spellInfo->ManaPerSecond = 0; break; + // Stonecore spells + case 95284: // Teleport (from entrance to Slabhide) + case 95285: // Teleport (from Slabhide to entrance) + spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_DEST_DB); + break; // Halls Of Origination spells // Temple Guardian Anhuur case 76606: // Disable Beacon Beams L diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp index 1cf0cc56242..36289fb1169 100644 --- a/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp +++ b/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp @@ -93,7 +93,9 @@ class boss_corborus : public CreatureScript void Reset() override { _Reset(); + countTrashingCharge = 0; + events.ScheduleEvent(EVENT_DAMPENING_WAVE, 10000); events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 15000); events.ScheduleEvent(EVENT_SUBMERGE, 36000); @@ -110,7 +112,7 @@ class boss_corborus : public CreatureScript stateIntro = IN_PROGRESS; - if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM))) + if (Creature* Millhouse = instance->GetCreature(DATA_MILLHOUSE_MANASTORM)) { Millhouse->InterruptNonMeleeSpells(true); Millhouse->RemoveAllAuras(); @@ -144,18 +146,18 @@ class boss_corborus : public CreatureScript instance->SetData(DATA_MILLHOUSE_EVENT_FACE, 0); // Open rock gate and cast visual from nearby worldtrigger - instance->HandleGameObject(instance->GetGuidData(GAMEOBJECT_CORBORUS_ROCKDOOR), true); + instance->SetData(DATA_HANDLE_CORBORUS_ROCKDOOR, 0); if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 60.0f)) worldtrigger->CastSpell(worldtrigger, SPELL_DOOR_BREAK, true); // Make Corborus charge - me->CastSpell(me, SPELL_RING_WYRM_CHARGE, true); + DoCast(me, SPELL_RING_WYRM_CHARGE, true); events.ScheduleEvent(EVENT_CORBORUS_KNOCKBACK, 1000); break; case EVENT_CORBORUS_KNOCKBACK: // Spawn Twilight Documents (quest gameobject) - if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM))) + if (Creature* Millhouse = instance->GetCreature(DATA_MILLHOUSE_MANASTORM)) Millhouse->CastSpell(Millhouse, SPELL_TWILIGHT_DOCUMENTS, true); // Knockback Millhouse and other mobs @@ -231,12 +233,14 @@ class boss_corborus : public CreatureScript void JustSummoned(Creature* summon) override { - if (summon->GetEntry() != NPC_TRASHING_CHARGE) - return; + if (summon->GetEntry() == NPC_TRASHING_CHARGE) + { + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_TRASHING_CHARGE_EFFECT); + summon->DespawnOrUnsummon(6000); + } - summon->SetReactState(REACT_PASSIVE); - summon->CastSpell(summon, SPELL_TRASHING_CHARGE_EFFECT); - summon->DespawnOrUnsummon(6000); + BossAI::JustSummoned(summon); } private: @@ -269,7 +273,7 @@ class npc_rock_borer : public CreatureScript void IsSummonedBy(Unit* summoner) override { me->SetInCombatState(false, summoner); - DoCast(SPELL_ROCK_BORER_EMERGE); + DoCast(me, SPELL_ROCK_BORER_EMERGE); } void UpdateAI(uint32 diff) override @@ -291,7 +295,7 @@ class npc_rock_borer : public CreatureScript me->SetReactState(REACT_AGGRESSIVE); break; case EVENT_ROCK_BORE: - DoCast(SPELL_ROCK_BORE); + DoCast(me, SPELL_ROCK_BORE); events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer break; default: diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp index 08d56f2fa50..c7fa900ff8b 100644 --- a/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp +++ b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp @@ -92,7 +92,7 @@ enum Events // Phase 2: Fury of Earth EVENT_EARTH_FURY_FLY_UP, EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM, - EVENT_EARTH_FURY_CHECK_SEAT0, + EVENT_EARTH_FURY_PREPARE_SHARD, EVENT_EARTH_FURY_LAUNCH_SHARD, EVENT_EARTH_FURY_FLY_DOWN, EVENT_START_ATTACK, @@ -101,12 +101,6 @@ enum Events EVENT_SEISMIC_SHARD_MOUNT }; -enum EventGroups -{ - EVENT_GROUP_PHASE_ONE, - EVENT_GROUP_ADDS, -}; - enum Points { POINT_NONE, @@ -122,7 +116,6 @@ Position const GroundPos = { 1331.82f, 980.314f, 207.542f }; Position const AbovePlatformPos = { 1336.21f, 960.813f, 215.0f }; // TO-DO: -// - Find out why NPCs summoned by boss are usually two times bigger than their normal size. // - Find more sniffs and script Force Grip spell (79351) class boss_high_priestess_azil : public CreatureScript @@ -132,11 +125,7 @@ class boss_high_priestess_azil : public CreatureScript struct boss_high_priestess_azilAI : public BossAI { - boss_high_priestess_azilAI(Creature* creature) : BossAI(creature, DATA_HIGH_PRIESTESS_AZIL) - { - ASSERT(creature->GetVehicleKit()); - } - + boss_high_priestess_azilAI(Creature* creature) : BossAI(creature, DATA_HIGH_PRIESTESS_AZIL) { } void Reset() override { _Reset(); @@ -146,9 +135,9 @@ class boss_high_priestess_azil : public CreatureScript me->SetReactState(REACT_PASSIVE); events.ScheduleEvent(EVENT_INTRO_MOVE, 2000); - events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE); - events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000,10000), EVENT_GROUP_PHASE_ONE); - events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000); + events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000,10000)); + events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000); events.ScheduleEvent(EVENT_ENERGY_SHIELD, urand(35000,36000)); events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 0); events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 40000); @@ -158,32 +147,16 @@ class boss_high_priestess_azil : public CreatureScript { _EnterCombat(); - DoCast(SPELL_ENERGY_SHIELD); + DoCast(me, SPELL_ENERGY_SHIELD); Talk(SAY_AGGRO); } void JustDied(Unit* /*killer*/) override { - Talk(SAY_DEATH); - } - - /* - void PassengerBoarded(Unit* who, int8 seatId, bool apply) override - { - if (!apply || who->GetEntry() != NPC_SEISMIC_SHARD) - return; + _JustDied(); - Movement::MoveSplineInit init(who); - init.DisableTransportPathTransformations(); - if (seatId == 0) - init.MoveTo(12.13748f, 0.0f, 2.442475f); - else if (seatId == 1) - init.MoveTo(12.13748f, 17.5f, 11.19248f); - else - init.MoveTo(12.13748f, -17.5f, 11.19248f); - init.Launch(); + Talk(SAY_DEATH); } - */ void MovementInform(uint32 type, uint32 id) override { @@ -195,6 +168,7 @@ class boss_high_priestess_azil : public CreatureScript case POINT_INTRO_MOVE: me->RemoveAurasDueToSpell(SPELL_ENERGY_SHIELD); me->SetReactState(REACT_AGGRESSIVE); + DoStartMovement(me->GetVictim()); break; case POINT_FLY_UP: me->SetCanFly(true); @@ -203,21 +177,22 @@ class boss_high_priestess_azil : public CreatureScript break; case POINT_ABOVE_PLATFORM: me->SetFacingTo(5.218534f); - DoCast(SPELL_EARTH_FURY_CASTING_VISUAL); - DoCast(SPELL_SEISMIC_SHARD_SUMMON_1); - DoCast(SPELL_SEISMIC_SHARD_SUMMON_2); - DoCast(SPELL_SEISMIC_SHARD_SUMMON_3); - events.ScheduleEvent(EVENT_EARTH_FURY_CHECK_SEAT0, 6700); + DoCast(me, SPELL_EARTH_FURY_CASTING_VISUAL); + DoCast(me, SPELL_SEISMIC_SHARD_SUMMON_1); + DoCast(me, SPELL_SEISMIC_SHARD_SUMMON_2); + DoCast(me, SPELL_SEISMIC_SHARD_SUMMON_3); + events.ScheduleEvent(EVENT_EARTH_FURY_PREPARE_SHARD, 6700); break; case POINT_GROUND: - DoCast(SPELL_EJECT_ALL_PASSENGERS); + DoCast(me, SPELL_EJECT_ALL_PASSENGERS); me->SetCanFly(false); me->SetDisableGravity(false); me->SetReactState(REACT_AGGRESSIVE); + DoStartMovement(me->GetVictim()); // Find more sniffs to correct these timers, this was copied from Reset() void. - events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE); - events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000, 10000), EVENT_GROUP_PHASE_ONE); - events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000); + events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000, 10000)); + events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000); break; default: break; @@ -244,20 +219,20 @@ class boss_high_priestess_azil : public CreatureScript case EVENT_CURSE_OF_BLOOD: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) DoCast(target, SPELL_CURSE_OF_BLOOD); - events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000)); break; case EVENT_FORCE_GRIP: DoCastVictim(SPELL_FORCE_GRIP); - events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000)); break; case EVENT_SUMMON_GRAVITY_WELL: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) DoCast(target, SPELL_SUMMON_GRAVITY_WELL); - events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, urand(13000, 15000), EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, urand(13000, 15000)); break; case EVENT_ENERGY_SHIELD: - events.CancelEventGroup(EVENT_GROUP_PHASE_ONE); - DoCast(SPELL_EARTH_FURY_ENERGY_SHIELD); + events.Reset(); + DoCast(me, SPELL_EARTH_FURY_ENERGY_SHIELD); events.ScheduleEvent(EVENT_EARTH_FURY, 0); break; case EVENT_EARTH_FURY: @@ -273,9 +248,8 @@ class boss_high_priestess_azil : public CreatureScript case EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM: me->GetMotionMaster()->MovePoint(POINT_ABOVE_PLATFORM, AbovePlatformPos); break; - case EVENT_EARTH_FURY_CHECK_SEAT0: - if (!me->GetVehicleKit()->GetPassenger(0)) - DoCast(SPELL_SEISMIC_SHARD_PREPARE); + case EVENT_EARTH_FURY_PREPARE_SHARD: + DoCast(me, SPELL_SEISMIC_SHARD_PREPARE); events.ScheduleEvent(EVENT_EARTH_FURY_LAUNCH_SHARD, 1800); break; case EVENT_EARTH_FURY_LAUNCH_SHARD: @@ -283,10 +257,10 @@ class boss_high_priestess_azil : public CreatureScript { me->SetFacingToObject(target); DoCast(target, SPELL_SEISMIC_SHARD_TARGETING); - DoCast(SPELL_SEISMIC_SHARD_LAUNCH); + DoCast(me, SPELL_SEISMIC_SHARD_LAUNCH); countSeismicShard -= 1; } - events.ScheduleEvent(countSeismicShard > 0 ? EVENT_EARTH_FURY_CHECK_SEAT0 : EVENT_EARTH_FURY_FLY_DOWN, 4800); + events.ScheduleEvent(countSeismicShard > 0 ? EVENT_EARTH_FURY_PREPARE_SHARD : EVENT_EARTH_FURY_FLY_DOWN, 4800); break; case EVENT_EARTH_FURY_FLY_DOWN: { @@ -369,8 +343,7 @@ public: { npc_gravity_wellAI(Creature* creature) : ScriptedAI(creature) { - me->SetReactState(REACT_PASSIVE); - DoCast(SPELL_GRAVITY_WELL_VISUAL); + DoCast(me, SPELL_GRAVITY_WELL_VISUAL); events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_DAMAGE, 3200); events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_PULL, 4500); if (!me->GetMap()->IsHeroic()) @@ -397,10 +370,10 @@ public: { case EVENT_GRAVITY_WELL_AURA_DAMAGE: me->RemoveAurasDueToSpell(SPELL_GRAVITY_WELL_VISUAL); - DoCast(SPELL_GRAVITY_WELL_AURA_DAMAGE); + DoCast(me, SPELL_GRAVITY_WELL_AURA_DAMAGE); break; case EVENT_GRAVITY_WELL_AURA_PULL: - DoCast(SPELL_GRAVITY_WELL_AURA_PULL); + DoCast(me, SPELL_GRAVITY_WELL_AURA_PULL); break; default: break; @@ -430,8 +403,7 @@ public: { instance = creature->GetInstanceScript(); me->SetDisableGravity(true); - me->SetReactState(REACT_PASSIVE); - DoCast(SPELL_SEISMIC_SHARD_VISUAL); + DoCast(me, SPELL_SEISMIC_SHARD_VISUAL); Movement::MoveSplineInit init(me); FillPath(me->GetPosition(), init.Path()); @@ -512,7 +484,7 @@ public: void HandleScript(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); - for (uint8 i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) caster->CastSpell(caster, SPELL_SUMMON_ADD_SOUTH, true); } @@ -548,7 +520,7 @@ public: void HandleScript(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); - for (uint8 i = 0; i < 10; i++) + for (int i = 0; i < 10; i++) caster->CastSpell(caster, SPELL_SUMMON_ADD_WEST, true); } @@ -652,15 +624,6 @@ public: }; // 79332 - Gravity Well (pull units within 10 yards) -class PulledRecentlyCheck -{ -public: - bool operator()(WorldObject* object) const - { - return (object->ToUnit() && object->ToUnit()->HasAura(SPELL_GRAVITY_WELL_PULL)); - } -}; - class spell_gravity_well_pull : public SpellScriptLoader { public: @@ -675,15 +638,9 @@ public: GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3)); } - void FilterTargets(std::list& unitList) - { - unitList.remove_if(PulledRecentlyCheck()); - } - void Register() override { BeforeCast += SpellCastFn(spell_gravity_well_pull_SpellScript::SetRadiusMod); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_pull_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); } }; @@ -693,34 +650,7 @@ public: } }; -// 86862 - Seismic Shard (forces target to cast 86863) -class spell_seismic_shard_prepare : public SpellScriptLoader -{ -public: - spell_seismic_shard_prepare() : SpellScriptLoader("spell_seismic_shard_prepare") { } - - class spell_seismic_shard_prepare_SpellScript : public SpellScript - { - PrepareSpellScript(spell_seismic_shard_prepare_SpellScript); - - void SetTarget(WorldObject*& target) - { - target = GetCaster()->FindNearestCreature(NPC_SEISMIC_SHARD, 50.0f); - } - - void Register() override - { - OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_prepare_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_seismic_shard_prepare_SpellScript(); - } -}; - -// 86863 - Seismic Shard (moves shard to seat 0) +// 86863 - Seismic Shard (makes shard reenter Azil) class spell_seismic_shard_change_seat : public SpellScriptLoader { public: @@ -730,23 +660,14 @@ public: { PrepareSpellScript(spell_seismic_shard_change_seat_SpellScript); - void SetTarget(WorldObject*& target) - { - if (InstanceScript* instance = GetCaster()->GetInstanceScript()) - target = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL)); - } - - void ChangeSeat(SpellEffIndex /*effIndex*/) + void ExitVehicle() { GetCaster()->ExitVehicle(); - if (GetHitUnit()->IsVehicle()) - GetCaster()->EnterVehicle(GetHitUnit(), 0); } void Register() override { - OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_change_seat_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY); - OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_change_seat_SpellScript::ChangeSeat, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + BeforeCast += SpellCastFn(spell_seismic_shard_change_seat_SpellScript::ExitVehicle); } }; @@ -800,7 +721,6 @@ void AddSC_boss_high_priestess_azil() new spell_gravity_well_damage_nearby(); new spell_gravity_well_damage(); new spell_gravity_well_pull(); - new spell_seismic_shard_prepare(); new spell_seismic_shard_change_seat(); new spell_seismic_shard(); } diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp index 0b260de944a..b5448acb556 100644 --- a/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp +++ b/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp @@ -89,8 +89,6 @@ class boss_ozruk : public CreatureScript events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, 5000); events.ScheduleEvent(EVENT_GROUND_SLAM, 10000); events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, 13000); - - RemoveBouncerSpikes(); } void EnterCombat(Unit* /*victim*/) override @@ -102,12 +100,13 @@ class boss_ozruk : public CreatureScript void JustSummoned(Creature* summon) override { - if (summon->GetEntry() != NPC_RUPTURE_CONTROLLER) - return; + if (summon->GetEntry() == NPC_RUPTURE_CONTROLLER) + { + summon->CastSpell(summon, SPELL_RUPTURE, true); + summon->DespawnOrUnsummon(10000); + } - summon->SetReactState(REACT_PASSIVE); - summon->CastSpell(summon, SPELL_RUPTURE, true); - summon->DespawnOrUnsummon(10000); + BossAI::JustSummoned(summon); } void DamageTaken(Unit* /*attacker*/, uint32 &damage) override @@ -116,14 +115,14 @@ class boss_ozruk : public CreatureScript return; DoCast(me, SPELL_ENRAGE); - me->Say(SAY_ENRAGE); + Talk(SAY_ENRAGE); } - void JustDied(Unit* killer) override + void JustDied(Unit* /*killer*/) override { - me->Say(SAY_DEATH, killer); // receiver is the killer, sniff source! + _JustDied(); - RemoveBouncerSpikes(); + Talk(SAY_DEATH); } void UpdateAI(uint32 diff) override @@ -133,7 +132,7 @@ class boss_ozruk : public CreatureScript events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_ELEMENTIUM_SPIKE_SHIELD)) + if (me->HasUnitState(UNIT_STATE_CASTING)) return; while (uint32 eventId = events.ExecuteEvent()) @@ -156,7 +155,7 @@ class boss_ozruk : public CreatureScript events.ScheduleEvent(EVENT_SHATTER, 10000); break; case EVENT_SHATTER: - RemoveBouncerSpikes(); + summons.DespawnEntry(NPC_BOUNCER_SPIKE); me->SetReactState(REACT_PASSIVE); me->AttackStop(); DoCast(me, SPELL_SHATTER); @@ -168,6 +167,7 @@ class boss_ozruk : public CreatureScript break; case EVENT_START_ATTACK: me->SetReactState(REACT_AGGRESSIVE); + DoStartMovement(me->GetVictim()); break; default: break; @@ -176,18 +176,6 @@ class boss_ozruk : public CreatureScript DoMeleeAttackIfReady(); } - - void RemoveBouncerSpikes() - { - Vehicle* vehicle = me->GetVehicleKit(); - if (!vehicle) - return; - - for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++) - if (Unit* passenger = vehicle->GetPassenger(i)) - if (Creature* creature = passenger->ToCreature()) - creature->RemoveFromWorld(); - } }; CreatureAI* GetAI(Creature* creature) const override @@ -229,7 +217,6 @@ public: if (!rupture) return; - rupture->SetReactState(REACT_PASSIVE); rupture->CastSpell(rupture, SPELL_RUPTURE_DAMAGE, true); } diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp index c5f0718e240..0b5b3e153be 100644 --- a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp +++ b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp @@ -199,7 +199,7 @@ class boss_slabhide : public CreatureScript events.ScheduleEvent(EVENT_STALACTITE, 400); break; case POINT_SLABHIDE_LAND: - //DoCast(SPELL_COOLDOWN_5S); // unknown purpose + //DoCast(me, SPELL_COOLDOWN_5S); // unknown purpose events.ScheduleEvent(EVENT_ATTACK, 1200); break; default: @@ -225,11 +225,12 @@ class boss_slabhide : public CreatureScript instance->SetData(DATA_SLABHIDE_ROCK_WALL, false); break; case EVENT_LAVA_FISSURE: - DoCast(SPELL_LAVA_FISSURE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_LAVA_FISSURE); events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000)); break; case EVENT_SAND_BLAST: - DoCast(SPELL_SAND_BLAST); + DoCast(me, SPELL_SAND_BLAST); events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 11000)); break; case EVENT_AIR_PHASE: @@ -248,7 +249,7 @@ class boss_slabhide : public CreatureScript me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); me->SetHover(true); - DoCast(SPELL_STALACTITE_SUMMON); + DoCast(me, SPELL_STALACTITE_SUMMON); events.ScheduleEvent(EVENT_LAND, 8000); break; @@ -267,7 +268,7 @@ class boss_slabhide : public CreatureScript events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000)); events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000)); - DoCast(SPELL_CRYSTAL_STORM); + DoCast(me, SPELL_CRYSTAL_STORM); me->SetReactState(REACT_AGGRESSIVE); break; default: @@ -315,8 +316,7 @@ public: { npc_lava_fissureAI(Creature* creature) : ScriptedAI(creature) { - me->SetReactState(REACT_PASSIVE); - me->CastSpell(me, SPELL_LAVA_FISSURE_CRACK, true); + DoCast(me, SPELL_LAVA_FISSURE_CRACK, true); events.ScheduleEvent(EVENT_LAVA_FISSURE_ERUPTION, 6000); } @@ -330,7 +330,7 @@ public: { case EVENT_LAVA_FISSURE_ERUPTION: me->RemoveAurasDueToSpell(SPELL_LAVA_FISSURE_CRACK); - me->CastSpell(me, SPELL_LAVA_FISSURE_ERUPTION, true); + DoCast(me, SPELL_LAVA_FISSURE_ERUPTION, true); me->DespawnOrUnsummon(14000); break; default: @@ -359,14 +359,16 @@ public: { npc_stalactite_triggerAI(Creature* creature) : ScriptedAI(creature) { - me->SetReactState(REACT_PASSIVE); me->SetDisableGravity(true); - me->CastSpell(me, SPELL_STALACTITE_SHADE, true); + DoCast(me, SPELL_STALACTITE_SHADE, true); events.ScheduleEvent(EVENT_STALACTITE_MISSLE, 5600); } void UpdateAI(uint32 diff) override { + if (events.Empty()) + return; + events.Update(diff); while (uint32 eventId = events.ExecuteEvent()) @@ -374,7 +376,7 @@ public: switch (eventId) { case EVENT_STALACTITE_MISSLE: - DoCast(SPELL_STALACTITE_MISSLE); + DoCast(me, SPELL_STALACTITE_MISSLE); me->DespawnOrUnsummon(11000); break; default: @@ -394,15 +396,6 @@ public: }; // 81035 - Stalactite (check if player is near to summon stalactite) -class NotPlayerCheck -{ - public: - bool operator()(WorldObject* object) const - { - return (object->GetTypeId() != TYPEID_PLAYER); - } -}; - class spell_s81035_stalactite : public SpellScriptLoader { public: @@ -412,11 +405,6 @@ public: { PrepareSpellScript(spell_s81035_stalactite_SpellScript); - void FilterTargets(std::list& targets) - { - targets.remove_if(NotPlayerCheck()); - } - void SummonStalactiteTrigger() { Unit* caster = GetCaster(); @@ -425,7 +413,6 @@ public: void Register() override { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s81035_stalactite_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); OnHit += SpellHitFn(spell_s81035_stalactite_SpellScript::SummonStalactiteTrigger); } }; diff --git a/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp b/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp index b2ac21a1edf..1e68c612616 100644 --- a/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp +++ b/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp @@ -34,6 +34,17 @@ // TO-DO: // - Find out spell IDs for both Stonecore Teleporters (spellclick). +ObjectData const creatureData[] = +{ + { NPC_MILLHOUSE_MANASTORM, DATA_MILLHOUSE_MANASTORM }, + { NPC_CORBORUS, DATA_CORBORUS }, + { NPC_SLABHIDE, DATA_SLABHIDE }, + { NPC_HIGH_PRIESTESS_AZIL, DATA_HIGH_PRIESTESS_AZIL }, + { NPC_STONECORE_TELEPORTER, DATA_STONECORE_TELEPORTER }, + { NPC_STONECORE_TELEPORTER_2, DATA_STONECORE_TELEPORTER_2 }, + { 0, 0 } // END +}; + class instance_stonecore : public InstanceMapScript { public: @@ -45,6 +56,7 @@ class instance_stonecore : public InstanceMapScript { SetHeaders(DataHeader); SetBossNumber(MAX_ENCOUNTER); + LoadObjectData(creatureData, nullptr); } void OnGameObjectCreate(GameObject* go) override @@ -67,27 +79,10 @@ class instance_stonecore : public InstanceMapScript { switch (creature->GetEntry()) { - case NPC_MILLHOUSE_MANASTORM: - millhouseGUID = creature->GetGUID(); - break; - case NPC_CORBORUS: - corobrusGUID = creature->GetGUID(); - break; - case NPC_SLABHIDE: - slabhideGUID = creature->GetGUID(); - break; - case NPC_HIGH_PRIESTESS_AZIL: - highPriestessAzilGUID = creature->GetGUID(); - break; case NPC_STONECORE_TELEPORTER: case NPC_STONECORE_TELEPORTER_2: - if (GetBossState(DATA_SLABHIDE) != DONE) - stonecoreTeleporterGUID[creature->GetEntry() - NPC_STONECORE_TELEPORTER] = creature->GetGUID(); - else // If Slabhide is already dead, no need to store teleporter guids - { - creature->CastSpell(creature, SPELL_TELEPORTER_ACTIVE_VISUAL, true); - creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - } + if (GetBossState(DATA_SLABHIDE) == DONE) + ActivateTeleporter(creature); break; default: break; @@ -95,7 +90,7 @@ class instance_stonecore : public InstanceMapScript // Check if creature is part of Millhouse event creature->SearchFormation(); - if (CreatureGroup* group = creature->GetFormation()) // TO-DO: Fix formations + if (CreatureGroup* group = creature->GetFormation()) { switch (group->GetId()) { @@ -109,6 +104,8 @@ class instance_stonecore : public InstanceMapScript break; } } + + InstanceScript::OnCreatureCreate(creature); } bool SetBossState(uint32 type, EncounterState state) override @@ -123,16 +120,9 @@ class instance_stonecore : public InstanceMapScript // Activate teleporters if (state == DONE) { - for (int8 i = 0; i < MAX_STONECORE_TELEPORTERS; i++) - { - if (Creature* teleporter = instance->GetCreature(stonecoreTeleporterGUID[i])) - { - teleporter->CastSpell(teleporter, SPELL_TELEPORTER_ACTIVE_VISUAL, true); - teleporter->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - } - } + ActivateTeleporter(GetCreature(DATA_STONECORE_TELEPORTER)); + ActivateTeleporter(GetCreature(DATA_STONECORE_TELEPORTER_2)); } - break; default: break; @@ -158,6 +148,9 @@ class instance_stonecore : public InstanceMapScript { switch (type) { + case DATA_HANDLE_CORBORUS_ROCKDOOR: + HandleGameObject(corborusRockDoorGUID, true); + break; case DATA_MILLHOUSE_EVENT_FACE: MillhouseEvent_Face(); break; @@ -179,35 +172,11 @@ class instance_stonecore : public InstanceMapScript } } - ObjectGuid GetGuidData(uint32 type) const override - { - switch (type) - { - case DATA_MILLHOUSE_MANASTORM: - return millhouseGUID; - case GAMEOBJECT_CORBORUS_ROCKDOOR: - return corborusRockDoorGUID; - case DATA_CORBORUS: - return corobrusGUID; - case DATA_SLABHIDE: - return slabhideGUID; - case DATA_HIGH_PRIESTESS_AZIL: - return highPriestessAzilGUID; - case NPC_STONECORE_TELEPORTER: - case NPC_STONECORE_TELEPORTER_2: - return stonecoreTeleporterGUID[type - NPC_STONECORE_TELEPORTER]; - default: - break; - } - - return ObjectGuid::Empty; - } - private: // Face Millhouse and other nearby mobs to Corborus void MillhouseEvent_Face() { - if (Creature* Millhouse = instance->GetCreature(millhouseGUID)) + if (Creature* Millhouse = GetCreature(DATA_MILLHOUSE_MANASTORM)) Millhouse->SetFacingTo(1.570796f); for (GuidVector::const_iterator i = millhouseLastGroupGUIDs.begin(); i != millhouseLastGroupGUIDs.end(); ++i) if (Creature* creature = instance->GetCreature(*i)) @@ -217,7 +186,7 @@ class instance_stonecore : public InstanceMapScript // Knock back Millhouse and other mobs void MillhouseEvent_Knockback() { - if (Creature* Millhouse = instance->GetCreature(millhouseGUID)) + if (Creature* Millhouse = GetCreature(DATA_MILLHOUSE_MANASTORM)) Millhouse->CastSpell(Millhouse, SPELL_RING_WYRM_KNOCKBACK, true); for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr) if (Creature* creature = instance->GetCreature(*itr)) @@ -227,7 +196,7 @@ class instance_stonecore : public InstanceMapScript // Despawn all mobs void MillhouseEvent_Despawn() { - if (Creature* Millhouse = instance->GetCreature(millhouseGUID)) + if (Creature* Millhouse = GetCreature(DATA_MILLHOUSE_MANASTORM)) Millhouse->DespawnOrUnsummon(3000); for (GuidVector::const_iterator itr = millhouseTrashGUIDs.begin(); itr != millhouseTrashGUIDs.end(); ++itr) if (Creature* creature = instance->GetCreature(*itr)) @@ -237,14 +206,18 @@ class instance_stonecore : public InstanceMapScript creature->DespawnOrUnsummon(3000); } - ObjectGuid millhouseGUID; + void ActivateTeleporter(Creature* teleporter) + { + if (!teleporter) + return; + + teleporter->CastSpell(teleporter, SPELL_TELEPORTER_ACTIVE_VISUAL, true); + teleporter->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + } + GuidVector millhouseTrashGUIDs; GuidVector millhouseLastGroupGUIDs; ObjectGuid corborusRockDoorGUID; - ObjectGuid corobrusGUID; - ObjectGuid slabhideGUID; - ObjectGuid highPriestessAzilGUID; - ObjectGuid stonecoreTeleporterGUID[2]; GuidVector slabhideRockWallGUIDs; EncounterState slabhideIntro; diff --git a/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp b/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp index abfb82284d3..3500290c358 100644 --- a/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp +++ b/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp @@ -30,11 +30,6 @@ enum Texts SAY_MILLHOUSE_EVENT_2 = 1, }; -enum NPCs -{ - NPC_GENERIC_TRIGGER_LAB = 40350, -}; - enum Spells { // Millhouse Manastorm @@ -96,6 +91,9 @@ Position const MillhousePointGroup2 = { 977.3045f, 895.2347f, 306.3298f }; Position const MillhousePointGroup3 = { 1049.823f, 871.4349f, 295.006f }; Position const MillhousePointGroup4 = { 1149.04f, 884.431f, 284.9406f }; +// TO-DO: +// - Millhouse Manastorm should face and cast SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, but he won't. :( + // 43391 - Millhouse Manastorm class npc_sc_millhouse_manastorm : public CreatureScript { @@ -175,27 +173,28 @@ class npc_sc_millhouse_manastorm : public CreatureScript me->CombatStop(true); me->DeleteThreatList(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - me->SetReactState(REACT_AGGRESSIVE); - switch (pointId) { case POINT_MILLHOUSE_GROUP_2: - if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f)) - me->SetFacingToObject(worldtrigger); // o: 5.497359f (sniff data) - me->CastSpell(me, SPELL_ANCHOR_HERE, true); - me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + me->SetReactState(REACT_AGGRESSIVE); + if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 200.0f)) + me->SetFacingToObject(worldtrigger); + DoCast(me, SPELL_ANCHOR_HERE); + DoCast(me, SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND); events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000); break; case POINT_MILLHOUSE_GROUP_3: + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + me->SetReactState(REACT_AGGRESSIVE); me->SetFacingTo(5.931499f); - me->CastSpell(me, SPELL_ANCHOR_HERE, true); - me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me); + DoCast(me, SPELL_ANCHOR_HERE); + DoCast(me, SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND); events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000); break; case POINT_MILLHOUSE_GROUP_4: me->SetFacingTo(3.455752f); - me->CastSpell(me, SPELL_ANCHOR_HERE, true); + DoCast(me, SPELL_ANCHOR_HERE); Talk(SAY_MILLHOUSE_EVENT_2); events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 1000); break; @@ -206,14 +205,14 @@ class npc_sc_millhouse_manastorm : public CreatureScript void UpdateAI(uint32 diff) override { - // Only update events if Millhouse is aggressive - if (me->GetReactState() != REACT_AGGRESSIVE) + // Do not update events if Millhouse is aggressive and has no combat. + if (!UpdateVictim() && me->GetReactState() == REACT_AGGRESSIVE) return; events.Update(diff); // Impending Doom is exception because it needs to be interrupted. - if (me->HasUnitState(UNIT_STATE_CASTING) && me->GetCurrentSpell(CURRENT_GENERIC_SPELL)->GetSpellInfo()->Id != SPELL_IMPENDING_DOOM_CHANNEL) + if (me->HasUnitState(UNIT_STATE_CASTING) && !me->FindCurrentSpellBySpellId(SPELL_IMPENDING_DOOM)) return; while (uint32 eventId = events.ExecuteEvent()) @@ -221,7 +220,7 @@ class npc_sc_millhouse_manastorm : public CreatureScript switch (eventId) { case EVENT_FROSTBOLT_VOLLEY: - DoCast(SPELL_FROSTBOLT_VOLLEY); + DoCastAOE(SPELL_FROSTBOLT_VOLLEY); events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 7000); break; case EVENT_SHADOWFURY: @@ -240,8 +239,8 @@ class npc_sc_millhouse_manastorm : public CreatureScript ScheduleEvents(); break; case EVENT_CAST_IMPENDING_DOOM: - DoCast(SPELL_IMPENDING_DOOM); - DoCast(SPELL_IMPENDING_DOOM_CHANNEL); + DoCast(me, SPELL_IMPENDING_DOOM); + DoCast(me, SPELL_IMPENDING_DOOM_CHANNEL); events.ScheduleEvent(EVENT_INTERRUPT_IMPENDING_DOOM, urand(15000,20000)); break; case EVENT_INTERRUPT_IMPENDING_DOOM: @@ -341,11 +340,6 @@ class spell_sc_twilight_documents : public SpellScriptLoader return true; } - void SetTarget(WorldObject*& target) - { - target = GetCaster()->FindNearestCreature(NPC_GENERIC_TRIGGER_LAB, 100.0f); - } - void SpawnGameObject(SpellEffIndex /*effIndex*/) { if (WorldLocation* loc = GetHitDest()) @@ -354,7 +348,6 @@ class spell_sc_twilight_documents : public SpellScriptLoader void Register() override { - OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_sc_twilight_documents_SpellScript::SetTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY); OnEffectHit += SpellEffectFn(spell_sc_twilight_documents_SpellScript::SpawnGameObject, EFFECT_0, SPELL_EFFECT_DUMMY); } }; @@ -372,7 +365,7 @@ class JumpCheck bool operator()(WorldObject* object) const { Player* player = object->ToPlayer(); - return (player && player->HasUnitState(UNIT_STATE_JUMPING)); + return (player && (player->IsFalling() || player->HasUnitState(UNIT_STATE_JUMPING))); } }; @@ -410,7 +403,7 @@ public: bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override { if (InstanceScript* instance = player->GetInstanceScript()) - if (Creature* corborus = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_CORBORUS))) + if (Creature* corborus = instance->GetCreature(DATA_CORBORUS)) corborus->AI()->DoAction(ACTION_CORBORUS_INTRO); return true; } @@ -424,7 +417,7 @@ public: bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override { if (InstanceScript* instance = player->GetInstanceScript()) - if (Creature* slabhide = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SLABHIDE))) + if (Creature* slabhide = instance->GetCreature(DATA_SLABHIDE)) slabhide->AI()->DoAction(ACTION_SLABHIDE_INTRO); return true; } diff --git a/src/server/scripts/Maelstrom/Stonecore/stonecore.h b/src/server/scripts/Maelstrom/Stonecore/stonecore.h index 98a9878e0d3..a13a0efad58 100644 --- a/src/server/scripts/Maelstrom/Stonecore/stonecore.h +++ b/src/server/scripts/Maelstrom/Stonecore/stonecore.h @@ -32,11 +32,16 @@ enum DataTypes // Additional Data DATA_MILLHOUSE_MANASTORM, DATA_MILLHOUSE_EVENT_FACE, + DATA_HANDLE_CORBORUS_ROCKDOOR, DATA_MILLHOUSE_EVENT_KNOCKBACK, DATA_MILLHOUSE_EVENT_DESPAWN, DATA_SLABHIDE_INTRO, DATA_SLABHIDE_ROCK_WALL, + + // Teleporters + DATA_STONECORE_TELEPORTER, + DATA_STONECORE_TELEPORTER_2, }; enum Misc -- cgit v1.2.3 From b7dff4e64454ffa7eb830771229d58ca27251932 Mon Sep 17 00:00:00 2001 From: Nayd Date: Sun, 28 Dec 2014 18:14:09 +0000 Subject: Core/Spells: Fix build in LoadSpellInfoCorrections() --- src/server/game/Spells/SpellMgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 46ec7553d02..811e6d9c0f9 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3621,7 +3621,7 @@ void SpellMgr::LoadSpellInfoCorrections() // Stonecore spells case 95284: // Teleport (from entrance to Slabhide) case 95285: // Teleport (from Slabhide to entrance) - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_DEST_DB); + const_cast(spellInfo->GetEffect(EFFECT_0))->TargetB = SpellImplicitTargetInfo(TARGET_DEST_DB); break; // Halls Of Origination spells // Temple Guardian Anhuur -- cgit v1.2.3 From 27137ca06e99209bd1a47a0ff7082ff14fcae8c9 Mon Sep 17 00:00:00 2001 From: pete318 Date: Sun, 28 Dec 2014 18:42:52 +0000 Subject: Scripts/Quests: Fix Quest A Spirit Guide - Ensures rep adjustment buff is always applied (overrides evade, implements existing evade + re-apply buff) - Removes un-owned ravagers with incorrect faction from DB (the correct ones are spawned with their masters without the DB entries) - Create some extra steps in the wolf's waypoints in order to generate some AI events for the Ryga NPC. I think it's a bit of a dirty solution, but it seems to work with minimal changes. - Created RP series of events with Ryga NPC and Ancestral Wolf Spirit (Ryga Kneels, talks to wolf, then returns to spawn position after around a minute). Closes #13619 Fix #4028 (cherry picked from commit f2444eedf92fce39f7685eafead61d88d4ad89ef) Conflicts: sql/updates/world/2014_12_28_02_world.sql --- sql/updates/world/2014_12_28_03_world.sql | 5 ++ .../scripts/Outland/zone_hellfire_peninsula.cpp | 53 ++++++++++++++++++++-- 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 sql/updates/world/2014_12_28_03_world.sql (limited to 'src') diff --git a/sql/updates/world/2014_12_28_03_world.sql b/sql/updates/world/2014_12_28_03_world.sql new file mode 100644 index 00000000000..bc44ddd1cd1 --- /dev/null +++ b/sql/updates/world/2014_12_28_03_world.sql @@ -0,0 +1,5 @@ +DELETE FROM `creature` WHERE `id`=19461; +DELETE FROM `script_waypoint` WHERE `entry`=17077 AND `pointid` IN (51, 52); +INSERT INTO `script_waypoint` (`entry`, `pointid`, `location_x`, `location_y`, `location_z`, `waittime`, `point_comment`) VALUES +(17077, 51, 519.146, 3886.7, 190.128, 10000, 'RYGA_WALK'), +(17077, 52, 519.146, 3886.7, 190.128, 1000, 'RYGA_RETURN'); diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index 79e6649495b..58f77f22f97 100644 --- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp +++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp @@ -140,8 +140,8 @@ enum AncestralWolf { EMOTE_WOLF_LIFT_HEAD = 0, EMOTE_WOLF_HOWL = 1, - SAY_WOLF_WELCOME = 2, - SPELL_ANCESTRAL_WOLF_BUFF = 29981, + SAY_WOLF_WELCOME = 0, + SPELL_ANCESTRAL_WOLF_BUFF = 29938, NPC_RYGA = 17123 }; @@ -166,11 +166,16 @@ public: void Reset() override { ryga = NULL; + } + + // Override Evade Mode event, recast buff that was removed by standard handler + void EnterEvadeMode() override + { + npc_escortAI::EnterEvadeMode(); DoCast(me, SPELL_ANCESTRAL_WOLF_BUFF, true); } void MoveInLineOfSight(Unit* who) override - { if (!ryga && who->GetEntry() == NPC_RYGA && me->IsWithinDistInMap(who, 15.0f)) if (Creature* temp = who->ToCreature()) @@ -188,10 +193,48 @@ public: break; case 2: Talk(EMOTE_WOLF_HOWL); + DoCast(me, SPELL_ANCESTRAL_WOLF_BUFF, true); + break; + // Move Ryga into position + case 48: + if (Creature* ryga = me->FindNearestCreature(NPC_RYGA,70)) + { + if (ryga->IsAlive() && !ryga->IsInCombat()) + { + ryga->SetWalk(true); + ryga->SetSpeed(MOVE_WALK, 1.5f); + ryga->GetMotionMaster()->MovePoint(0, 517.340698f, 3885.03975f, 190.455978f, true); + Reset(); + } + } break; + // Ryga Kneels and welcomes spirit wolf case 50: - if (ryga && ryga->IsAlive() && !ryga->IsInCombat()) - ryga->AI()->Talk(SAY_WOLF_WELCOME); + if (Creature* ryga = me->FindNearestCreature(NPC_RYGA,70)) + { + if (ryga->IsAlive() && !ryga->IsInCombat()) + { + ryga->SetFacingTo(0.776773f); + ryga->SetStandState(UNIT_STAND_STATE_KNEEL); + ryga->AI()->Talk(SAY_WOLF_WELCOME); + Reset(); + } + } + break; + // Ryga returns to spawn point + case 51: + if (Creature* ryga = me->FindNearestCreature(NPC_RYGA,70)) + { + if (ryga->IsAlive() && !ryga->IsInCombat()) + { + float fRetX, fRetY, fRetZ, fRetO; + ryga->GetRespawnPosition(fRetX, fRetY, fRetZ, &fRetO); + ryga->SetHomePosition(fRetX, fRetY, fRetZ, fRetO); + ryga->SetStandState(UNIT_STAND_STATE_STAND); + ryga->GetMotionMaster()->MoveTargetedHome(); + Reset(); + } + } break; } } -- cgit v1.2.3