aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoret65 <et65@ashbringer.fr>2014-12-28 19:50:19 +0100
committeret65 <et65@ashbringer.fr>2014-12-28 19:50:19 +0100
commite46921748d9173f0dcaa32f8a53626c21cf4a2a2 (patch)
treee9467c092c4c9189b34ac10e95bc684c7d77ce3e /src
parent4f557347ce26dcb3d7ce697ecd203ff92da5198a (diff)
parent27137ca06e99209bd1a47a0ff7082ff14fcae8c9 (diff)
Merge remote-tracking branch 'trinitycore/6.x' into 6.x
Diffstat (limited to 'src')
-rw-r--r--src/server/bnetserver/Realms/WorldListener.cpp3
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp2
-rw-r--r--src/server/game/Accounts/RBAC.h1
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp1329
-rw-r--r--src/server/game/Achievements/AchievementMgr.h133
-rw-r--r--src/server/game/DataStores/DB2Stores.h1
-rw-r--r--src/server/game/DataStores/DBCEnums.h19
-rw-r--r--src/server/game/DataStores/DBCStores.cpp25
-rw-r--r--src/server/game/DataStores/DBCStores.h4
-rw-r--r--src/server/game/DataStores/DBCStructure.h608
-rw-r--r--src/server/game/DataStores/DBCfmt.h8
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp22
-rw-r--r--src/server/game/Guilds/Guild.cpp6
-rw-r--r--src/server/game/Guilds/Guild.h2
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp77
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp22
-rw-r--r--src/server/game/Handlers/TradeHandler.cpp4
-rw-r--r--src/server/game/Server/Packets/AchievementPackets.cpp74
-rw-r--r--src/server/game/Server/Packets/AchievementPackets.h93
-rw-r--r--src/server/game/Server/Packets/GameObjectPackets.cpp28
-rw-r--r--src/server/game/Server/Packets/GameObjectPackets.h51
-rw-r--r--src/server/game/Server/Packets/QueryPackets.cpp41
-rw-r--r--src/server/game/Server/Packets/QueryPackets.h36
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp17
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h12
-rw-r--r--src/server/game/Server/WorldSession.cpp23
-rw-r--r--src/server/game/Server/WorldSession.h13
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/Spells/SpellMgr.cpp5
-rw-r--r--src/server/game/World/World.cpp16
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp2
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp26
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp154
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp39
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp39
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp95
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/stonecore.cpp53
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/stonecore.h5
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp2
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp1
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp26
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/oculus.h12
-rw-r--r--src/server/scripts/Outland/zone_hellfire_peninsula.cpp53
-rw-r--r--src/server/scripts/Spells/spell_mage.cpp69
-rw-r--r--src/server/scripts/Spells/spell_quest.cpp28
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.h2
-rw-r--r--src/server/shared/Networking/MessageBuffer.h8
-rw-r--r--src/server/shared/Networking/Socket.h3
-rw-r--r--src/server/worldserver/worldserver.conf.dist16
51 files changed, 1740 insertions, 1574 deletions
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);
+ }
}
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 6f14b3a04a8..2e86a78148a 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);
}
}
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/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<class T>
AchievementMgr<T>::~AchievementMgr() { }
template<class T>
-void AchievementMgr<T>::SendPacket(WorldPacket* data) const { }
+void AchievementMgr<T>::SendPacket(WorldPacket const* data) const { }
template<>
-void AchievementMgr<Guild>::SendPacket(WorldPacket* data) const
+void AchievementMgr<Guild>::SendPacket(WorldPacket const* data) const
{
GetOwner()->BroadcastPacket(data);
}
template<>
-void AchievementMgr<Player>::SendPacket(WorldPacket* data) const
+void AchievementMgr<Player>::SendPacket(WorldPacket const* data) const
{
GetOwner()->GetSession()->SendPacket(data);
}
template<class T>
-void AchievementMgr<T>::RemoveCriteriaProgress(AchievementCriteriaEntry const* entry)
+void AchievementMgr<T>::RemoveCriteriaProgress(AchievementCriteria const* entry)
{
if (!entry)
return;
@@ -429,7 +430,7 @@ void AchievementMgr<T>::RemoveCriteriaProgress(AchievementCriteriaEntry const* e
}
template<>
-void AchievementMgr<Guild>::RemoveCriteriaProgress(AchievementCriteriaEntry const* entry)
+void AchievementMgr<Guild>::RemoveCriteriaProgress(AchievementCriteria const* entry)
{
if (!entry)
return;
@@ -474,27 +475,28 @@ void AchievementMgr<T>::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<class T>
void AchievementMgr<T>::SaveToDB(SQLTransaction& /*trans*/)
{
}
-
template<>
void AchievementMgr<Player>::SaveToDB(SQLTransaction& trans)
{
@@ -571,6 +572,7 @@ void AchievementMgr<Player>::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<Player>::SaveToDB(SQLTransaction& trans)
iter->second.changed = false;
}
}
+ */
}
template<>
@@ -626,6 +629,7 @@ void AchievementMgr<Guild>::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<Guild>::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<class T>
void AchievementMgr<T>::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult)
{
@@ -682,6 +686,7 @@ void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, P
while (achievementResult->NextRow());
}
+ /*
if (criteriaResult)
{
time_t now = time(NULL);
@@ -692,7 +697,7 @@ void AchievementMgr<Player>::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<Player>::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<Player>::LoadFromDB(PreparedQueryResult achievementResult, P
}
while (criteriaResult->NextRow());
}
+ */
}
template<>
@@ -745,6 +751,7 @@ void AchievementMgr<Guild>::LoadFromDB(PreparedQueryResult achievementResult, Pr
while (achievementResult->NextRow());
}
+ /*
if (criteriaResult)
{
time_t now = time(NULL);
@@ -756,7 +763,7 @@ void AchievementMgr<Guild>::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<Guild>::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<HighGuid::Player>(guid);
+ progress.PlayerGUID = ObjectGuid::Create<HighGuid::Player>(guid);
progress.changed = false;
} while (criteriaResult->NextRow());
}
+ */
}
template<class T>
@@ -840,7 +848,7 @@ void AchievementMgr<Guild>::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<T>::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<Guild>::SendAchievementEarned(AchievementEntry const* achiev
}
template<class T>
-void AchievementMgr<T>::SendCriteriaUpdate(AchievementCriteriaEntry const* /*entry*/, CriteriaProgress const* /*progress*/, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const
+void AchievementMgr<T>::SendCriteriaUpdate(AchievementCriteria const* /*criteria*/, CriteriaProgress const* /*progress*/, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const
{
}
template<>
-void AchievementMgr<Player>::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const
+void AchievementMgr<Player>::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<Guild>::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const
+void AchievementMgr<Guild>::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<Guild>::SendAllTrackedCriterias(Player* receiver, std::set<u
for (std::set<uint32>::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<Guild>::SendAllTrackedCriterias(Player* receiver, std::set<u
for (std::set<uint32>::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<T>::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 <typename T> static bool IsGuild() { return false; }
template<> bool IsGuild<Guild>() { return true; }
@@ -1151,18 +1147,12 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
if (IsGuild<T>() && !sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED))
return;
- AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, IsGuild<T>());
- for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i)
+ AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, IsGuild<T>());
+ 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<T>::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<T>::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<T>::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<T>::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<T>::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<T>::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<T>::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<T>::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<class T>
-bool AchievementMgr<T>::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement)
+bool AchievementMgr<T>::IsCompletedCriteriaTree(AchievementCriteriaTree const* tree)
{
+ AchievementEntry const* achievement = tree->Achievement;
if (!achievement)
return false;
@@ -1513,116 +1507,109 @@ bool AchievementMgr<T>::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<class T>
+bool AchievementMgr<T>::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
@@ -1680,70 +1667,40 @@ void AchievementMgr<T>::CompletedCriteriaFor(AchievementEntry const* achievement
}
template<class T>
+uint64 AchievementMgr<T>::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<class T>
bool AchievementMgr<T>::IsCompletedAchievement(AchievementEntry const* entry)
{
// counter can never complete
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<class T>
-CriteriaProgress* AchievementMgr<T>::GetCriteriaProgress(AchievementCriteriaEntry const* entry)
+CriteriaProgress* AchievementMgr<T>::GetCriteriaProgress(AchievementCriteria const* entry)
{
CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID);
@@ -1754,25 +1711,44 @@ CriteriaProgress* AchievementMgr<T>::GetCriteriaProgress(AchievementCriteriaEntr
}
template<class T>
-void AchievementMgr<T>::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype)
+void AchievementMgr<T>::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<T>::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<T>::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<class T>
@@ -1835,8 +1816,10 @@ void AchievementMgr<T>::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<T>::StartTimedAchievement(AchievementCriteriaTimedTypes /*ty
template<>
void AchievementMgr<Player>::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<class T>
void AchievementMgr<T>::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<class T>
void AchievementMgr<T>::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<Guild>::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<Guild>::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<Guild>::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<Guild>::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<T>::HasAchieved(uint32 achievementId) const
}
template<class T>
-bool AchievementMgr<T>::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer)
+bool AchievementMgr<T>::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<T>::CanUpdateCriteria(AchievementCriteriaEntry const* criter
}
template<class T>
-bool AchievementMgr<T>::ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* referencePlayer) const
+bool AchievementMgr<T>::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<class T>
-bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* achievementCriteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const
+bool AchievementMgr<T>::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<T>::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<T>::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<T>::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<T>::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<T>::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<T>::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<T>::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<T>::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<T>::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<T>::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<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
}
template<class T>
-bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 /*miscValue2*/, Unit const* unit, Player* referencePlayer) const
+bool AchievementMgr<T>::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<Guild>;
template class AchievementMgr<Player>;
//==========================================================
+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<uint32 /*criteriaTreeID*/, AchievementEntry const*> 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<AchievementCriteriaTree*>(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<AchievementEntry*>(achievement)->MapID = 631; // Correct map requirement (currently has Ulduar)
+ const_cast<AchievementEntry*>(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<AchievementCriteriaEntry const*> AchievementCriteriaEntryList;
-typedef std::vector<AchievementEntry const*> AchievementEntryList;
+struct ModifierTreeNode
+{
+ ModifierTreeEntry const* Entry;
+ std::vector<ModifierTreeNode const*> Children;
+};
+
+typedef std::unordered_map<uint32, ModifierTreeNode*> ModifierTreeMap;
+
+struct AchievementCriteria
+{
+ uint32 ID;
+ CriteriaEntry const* Entry;
+ ModifierTreeNode const* Modifier;
+};
+
+typedef std::vector<AchievementCriteria const*> AchievementCriteriaList;
+typedef std::unordered_map<uint32, AchievementCriteria*> AchievementCriteriaMap;
-typedef std::unordered_map<uint32, AchievementCriteriaEntryList> AchievementCriteriaListByAchievement;
-typedef std::unordered_map<uint32, AchievementEntryList> AchievementListByReferencedId;
+struct AchievementCriteriaTree
+{
+ uint32 ID;
+ CriteriaTreeEntry const* Entry;
+ AchievementEntry const* Achievement;
+ AchievementCriteria const* Criteria;
+ std::vector<AchievementCriteriaTree const*> Children;
+};
+
+typedef std::unordered_map<uint32, AchievementCriteriaTree*> AchievementCriteriaTreeMap;
+typedef std::vector<AchievementCriteriaTree const*> AchievementCriteriaTreeList;
+typedef std::vector<AchievementEntry const*> AchievementEntryList;
+typedef std::unordered_map<uint32, AchievementCriteriaTreeList> AchievementCriteriaTreeByCriteriaMap;
+
+typedef std::unordered_map<uint32, AchievementEntryList> 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<uint32, uint32> 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<uint32 /*achievementId*/, uint32 /*instanceId*/> 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/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 <string>
#include <map>
+#include "SharedDefines.h"
extern DB2Storage<BroadcastTextEntry> sBroadcastTextStore;
extern DB2Storage<HolidaysEntry> sHolidaysStore;
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 9aefb440d98..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
{
@@ -611,6 +613,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/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 <AchievementEntry> sAchievementStore(Achievementfmt);
-DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt);
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
DBCStorage <ArmorLocationEntry> sArmorLocationStore(ArmorLocationfmt);
DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt);
@@ -85,6 +84,8 @@ DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore(CreatureModelDatafmt);
DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt);
DBCStorage <CreatureTypeEntry> sCreatureTypeStore(CreatureTypefmt);
+DBCStorage <CriteriaEntry> sCriteriaStore(Criteriafmt);
+DBCStorage <CriteriaTreeEntry> sCriteriaTreeStore(CriteriaTreefmt);
DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore(CurrencyTypesfmt);
uint32 PowersByClass[MAX_CLASSES][MAX_POWERS];
@@ -163,6 +164,7 @@ DBCStorage <MapEntry> sMapStore(MapEntryfmt);
DBCStorage <MapDifficultyEntry> sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading
MapDifficultyMap sMapDifficultyMap;
+DBCStorage <ModifierTreeEntry> sModifierTreeStore(ModifierTreefmt);
DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt);
DBCStorage <MountCapabilityEntry> sMountCapabilityStore(MountCapabilityfmt);
DBCStorage <MountTypeEntry> sMountTypeStore(MountTypefmt);
@@ -240,19 +242,13 @@ typedef std::list<std::string> 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<class T>
inline void LoadDBC(uint32& availableDbcLocales, StoreProblemList& errors, DBCStorage<T>& 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<class T>
inline void LoadGameTable(StoreProblemList& errors, std::string const& tableName, GameTable<T>& 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 <AchievementEntry> sAchievementStore;
-extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
extern DBCStorage <AreaGroupEntry> sAreaGroupStore;
extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
@@ -156,6 +155,8 @@ extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore;
extern DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore;
extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore;
extern DBCStorage <CreatureTypeEntry> sCreatureTypeStore;
+extern DBCStorage <CriteriaEntry> sCriteriaStore;
+extern DBCStorage <CriteriaTreeEntry> sCriteriaTreeStore;
extern DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore;
extern DBCStorage <DestructibleModelDataEntry> sDestructibleModelDataStore;
extern DBCStorage <DungeonEncounterEntry> sDungeonEncounterStore;
@@ -217,6 +218,7 @@ extern DBCStorage <LockEntry> sLockStore;
extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
extern DBCStorage <MapEntry> sMapStore;
extern DBCStorage <MinorTalentEntry> sMinorTalentStore;
+extern DBCStorage <ModifierTreeEntry> sModifierTreeStore;
extern DBCStorage <MountCapabilityEntry> sMountCapabilityStore;
extern DBCStorage <MountTypeEntry> sMountTypeStore;
extern DBCStorage <NameGenEntry> 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<uint32>, X - skip<uint8>, 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/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())
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 367f1f57d3a..904600a2481 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);
@@ -20844,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));
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<uint32>
{
std::set<uint32> criteriaIds;
+ /*
for (std::set<uint32>::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/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/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);
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 <http://www.trinitycore.org/>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <http://www.trinitycore.org/>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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<EarnedAchievement> Earned;
+ std::vector<CriteriaProgress> 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/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 <http://www.trinitycore.org/>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <http://www.trinitycore.org/>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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<int32> 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 e18e5e984ac..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 PacketClass, void(WorldSession::*HandlerFunction)(PacketClass&)>
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 );
@@ -709,14 +710,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 +868,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);
@@ -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/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/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<OpcodeClient>(packet->GetOpcode())];
try
{
@@ -361,7 +358,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
"Player is currently not in world yet.", GetOpcodeNameForLogging(static_cast<OpcodeClient>(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<OpcodeClient>(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
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
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;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 544abc9ca87..811e6d9c0f9 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)
+ const_cast<SpellEffectInfo*>(spellInfo->GetEffect(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/game/World/World.cpp b/src/server/game/World/World.cpp
index eddad11e593..7195c58ae00 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)
{
@@ -1679,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...");
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/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)
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<WorldObject*>& 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<WorldObject*>& 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
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<Unit*, bool>
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;
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/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
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;
}
}
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();
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);
}
};
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 <cassert>
+#include <list>
+#include "Common.h"
class DB2FileLoader
{
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<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
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
@@ -3250,6 +3250,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
# Default: 0 (with precision)