aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/Server/AuthSocket.cpp16
-rw-r--r--src/server/authserver/authserver.conf.dist7
-rw-r--r--src/server/collision/CMakeLists.txt1
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp4
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp4
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp44
-rw-r--r--src/server/game/Accounts/AccountMgr.cpp22
-rw-r--r--src/server/game/Battlegrounds/ArenaScore.h93
-rw-r--r--src/server/game/Battlegrounds/ArenaTeam.h2
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp133
-rw-r--r--src/server/game/Battlegrounds/Battleground.h59
-rw-r--r--src/server/game/Battlegrounds/BattlegroundMgr.cpp170
-rw-r--r--src/server/game/Battlegrounds/BattlegroundMgr.h1
-rw-r--r--src/server/game/Battlegrounds/BattlegroundScore.h120
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp21
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAB.h39
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp227
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAV.h272
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp13
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundBE.h3
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp3
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp17
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundEY.h33
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp26
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundIC.h40
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp3
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp3
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp3
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp18
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundSA.h47
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp16
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundWS.h39
-rw-r--r--src/server/game/CMakeLists.txt2
-rw-r--r--src/server/game/DataStores/DBCEnums.h33
-rw-r--r--src/server/game/DataStores/DBCStores.cpp26
-rw-r--r--src/server/game/DataStores/DBCStores.h5
-rw-r--r--src/server/game/DataStores/DBCStructure.h21
-rw-r--r--src/server/game/DataStores/DBCfmt.h2
-rw-r--r--src/server/game/DungeonFinding/LFGScripts.cpp2
-rw-r--r--src/server/game/DungeonFinding/LFGScripts.h2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp81
-rw-r--r--src/server/game/Entities/Creature/Creature.h8
-rw-r--r--src/server/game/Entities/DynamicObject/DynamicObject.cpp15
-rw-r--r--src/server/game/Entities/DynamicObject/DynamicObject.h2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp59
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h3
-rw-r--r--src/server/game/Entities/Item/ItemPrototype.h2
-rw-r--r--src/server/game/Entities/Object/Object.cpp5
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.cpp75
-rw-r--r--src/server/game/Entities/Player/Player.h8
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp41
-rw-r--r--src/server/game/Entities/Transport/Transport.h11
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp219
-rw-r--r--src/server/game/Entities/Unit/Unit.h5
-rwxr-xr-xsrc/server/game/Entities/Vehicle/Vehicle.cpp10
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp30
-rw-r--r--src/server/game/Globals/ObjectMgr.h2
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.cpp7
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Handlers/BattleGroundHandler.cpp2
-rw-r--r--src/server/game/Handlers/CalendarHandler.cpp39
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp23
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp4
-rw-r--r--src/server/game/Handlers/LootHandler.cpp12
-rw-r--r--src/server/game/Handlers/MailHandler.cpp7
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp23
-rw-r--r--src/server/game/Handlers/SkillHandler.cpp3
-rw-r--r--src/server/game/Loot/LootMgr.h6
-rw-r--r--src/server/game/Maps/Map.cpp8
-rw-r--r--src/server/game/Miscellaneous/Language.h3
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h9
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp4
-rw-r--r--src/server/game/Scripting/ScriptLoader.cpp14
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp52
-rw-r--r--src/server/game/Scripting/ScriptMgr.h49
-rw-r--r--src/server/game/Server/WorldSession.cpp12
-rw-r--r--src/server/game/Server/WorldSession.h6
-rw-r--r--src/server/game/Server/WorldSocket.cpp59
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp121
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp57
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h1
-rw-r--r--src/server/game/Spells/Spell.cpp38
-rw-r--r--src/server/game/Spells/Spell.h2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp74
-rw-r--r--src/server/game/Spells/SpellInfo.cpp6
-rw-r--r--src/server/game/Spells/SpellMgr.cpp9
-rw-r--r--src/server/game/Spells/SpellMgr.h13
-rw-r--r--src/server/game/World/World.cpp6
-rw-r--r--src/server/game/World/World.h3
-rw-r--r--src/server/scripts/CMakeLists.txt2
-rw-r--r--src/server/scripts/Commands/cs_account.cpp11
-rw-r--r--src/server/scripts/Commands/cs_go.cpp32
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp25
-rw-r--r--src/server/scripts/Custom/CMakeLists.txt3
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp8
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp8
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp8
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp256
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp438
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h38
-rw-r--r--src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp18
-rw-r--r--src/server/scripts/Events/CMakeLists.txt4
-rw-r--r--src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp101
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp18
-rw-r--r--src/server/scripts/Northrend/CMakeLists.txt1
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp14
-rw-r--r--src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp8
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp16
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp10
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp1
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp1
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp1
-rw-r--r--src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp4
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp4
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp8
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp4
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp10
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp39
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp124
-rw-r--r--src/server/scripts/Northrend/zone_crystalsong_forest.cpp14
-rw-r--r--src/server/scripts/Northrend/zone_dalaran.cpp1
-rw-r--r--src/server/scripts/Northrend/zone_dragonblight.cpp9
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp (renamed from src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp)95
-rw-r--r--src/server/scripts/Outland/CMakeLists.txt2
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp89
-rw-r--r--src/server/scripts/Spells/spell_warlock.cpp4
-rw-r--r--src/server/scripts/World/CMakeLists.txt15
-rw-r--r--src/server/scripts/World/action_ip_logger.cpp315
-rw-r--r--src/server/scripts/World/areatrigger_scripts.cpp31
-rw-r--r--src/server/scripts/World/go_scripts.cpp5
-rw-r--r--src/server/scripts/World/guards.cpp6
-rw-r--r--src/server/scripts/World/mob_generic_creature.cpp2
-rw-r--r--src/server/scripts/World/npc_innkeeper.cpp2
-rw-r--r--src/server/scripts/World/npcs_special.cpp69
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.cpp12
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.h7
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.cpp376
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.h135
-rw-r--r--src/server/shared/Utilities/Util.cpp9
-rw-r--r--src/server/shared/Utilities/Util.h9
-rw-r--r--src/server/worldserver/CMakeLists.txt1
-rw-r--r--src/server/worldserver/worldserver.conf.dist15
-rw-r--r--src/tools/mmaps_generator/CMakeLists.txt2
-rw-r--r--src/tools/mmaps_generator/MapBuilder.cpp32
-rw-r--r--src/tools/mmaps_generator/MapBuilder.h20
149 files changed, 3154 insertions, 2188 deletions
diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp
index c7bb600024a..4ddad3e6eb0 100644
--- a/src/server/authserver/Server/AuthSocket.cpp
+++ b/src/server/authserver/Server/AuthSocket.cpp
@@ -715,13 +715,25 @@ bool AuthSocket::_HandleLogonProof()
char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 };
socket().send(data, sizeof(data));
- TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ());
+ TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0);
+
+ // We can not include the failed account login hook. However, this is a workaround to still log this.
+ if (sConfigMgr->GetBoolDefault("Additional.IP.Based.Login.Logging", false))
+ {
+ PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING);
+ logstmt->setString(0, _login);
+ logstmt->setString(1, socket().getRemoteAddress());
+ logstmt->setString(2, "Logged on failed AccountLogin due wrong password");
+
+ LoginDatabase.Execute(logstmt);
+ }
+
if (MaxWrongPassCount > 0)
{
//Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
- PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS);
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS);
stmt->setString(0, _login);
LoginDatabase.Execute(stmt);
diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist
index 83edf9669ac..b7dee9ac08b 100644
--- a/src/server/authserver/authserver.conf.dist
+++ b/src/server/authserver/authserver.conf.dist
@@ -148,6 +148,13 @@ LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth"
LoginDatabase.WorkerThreads = 1
#
+# Wrong.Password.Login.Logging
+# Description: Additionally log attempted wrong password logging
+# Default: 0 - (Disabled)
+# 1 - (Enabled)
+
+Wrong.Password.Login.Logging = 0
+#
###################################################################################################
###################################################################################################
diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt
index a83bb9dad1c..a2024bff7cb 100644
--- a/src/server/collision/CMakeLists.txt
+++ b/src/server/collision/CMakeLists.txt
@@ -34,6 +34,7 @@ include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index 7c640f9a66d..8032568434f 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -183,7 +183,11 @@ void PetAI::UpdateAI(uint32 diff)
}
if (spellInfo->HasEffect(SPELL_EFFECT_JUMP_DEST))
+ {
+ if (!spellUsed)
+ delete spell;
continue; // Pets must only jump to target
+ }
// No enemy, check friendly
if (!spellUsed)
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index ecaa20284d7..af47b52f500 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -537,9 +537,9 @@ void SmartAI::JustRespawned()
me->SetVisible(true);
if (me->getFaction() != me->GetCreatureTemplate()->faction)
me->RestoreFaction();
- GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN);
mJustReset = true;
JustReachedHome();
+ GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN);
mFollowGuid = 0;//do not reset follower on Reset(), we need it after combat evade
mFollowDist = 0;
mFollowAngle = 0;
@@ -944,7 +944,7 @@ class SmartTrigger : public AreaTriggerScript
}
};
-void AddSC_SmartSCripts()
+void AddSC_SmartScripts()
{
new SmartTrigger();
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 2647368559c..114a48c60ca 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -488,9 +488,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
case SMART_ACTION_CAST:
{
- if (!me)
- break;
-
ObjectList* targets = GetTargets(e, unit);
if (!targets)
break;
@@ -502,31 +499,36 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.cast.spell))
{
- if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
- me->InterruptNonMeleeSpells(false);
-
- if (e.action.cast.flags & SMARTCAST_COMBAT_MOVE)
+ if (me)
{
- // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed
- // unless target is outside spell range, out of mana, or LOS.
+ if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
+ me->InterruptNonMeleeSpells(false);
- bool _allowMove = false;
- SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell);
- int32 mana = me->GetPower(POWER_MANA);
+ if (e.action.cast.flags & SMARTCAST_COMBAT_MOVE)
+ {
+ // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed
+ // unless target is outside spell range, out of mana, or LOS.
+
+ bool _allowMove = false;
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell);
+ int32 mana = me->GetPower(POWER_MANA);
- if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) ||
- me->GetDistance(*itr) < spellInfo->GetMinRange(true) ||
- !me->IsWithinLOSInMap(*itr) ||
- mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask()))
+ if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) ||
+ me->GetDistance(*itr) < spellInfo->GetMinRange(true) ||
+ !me->IsWithinLOSInMap(*itr) ||
+ mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask()))
_allowMove = true;
- CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove);
- }
+ CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove);
+ }
- me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED));
+ me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED));
+ }
+ else if (go)
+ go->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED));
- TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: Creature %u casts spell %u on target %u with castflags %u",
- me->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags);
+ TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: %s: %u casts spell %u on target %u with castflags %u",
+ GetLogNameForGuid(me ? me->GetGUID() : go->GetGUID()), me ? me->GetGUIDLow() : go->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags);
}
else
TC_LOG_DEBUG("scripts.ai", "Spell %u not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: " UI64FMTD " Entry: %u Type: %u) already has the aura", e.action.cast.spell, (*itr)->GetGUID(), (*itr)->GetEntry(), uint32((*itr)->GetTypeId()));
diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp
index 773e169e5c2..ff30fe7ba35 100644
--- a/src/server/game/Accounts/AccountMgr.cpp
+++ b/src/server/game/Accounts/AccountMgr.cpp
@@ -21,6 +21,7 @@
#include "DatabaseEnv.h"
#include "ObjectAccessor.h"
#include "Player.h"
+#include "ScriptMgr.h"
#include "Util.h"
#include "SHA1.h"
#include "WorldSession.h"
@@ -166,10 +167,16 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass
std::string username;
if (!GetName(accountId, username))
+ {
+ sScriptMgr->OnFailedPasswordChange(accountId);
return AOR_NAME_NOT_EXIST; // account doesn't exist
+ }
if (utf8length(newPassword) > MAX_ACCOUNT_STR)
+ {
+ sScriptMgr->OnFailedPasswordChange(accountId);
return AOR_PASS_TOO_LONG;
+ }
normalizeString(username);
normalizeString(newPassword);
@@ -189,6 +196,7 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass
LoginDatabase.Execute(stmt);
+ sScriptMgr->OnPasswordChange(accountId);
return AOR_OK;
}
@@ -197,10 +205,16 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail)
std::string username;
if (!GetName(accountId, username))
+ {
+ sScriptMgr->OnFailedEmailChange(accountId);
return AOR_NAME_NOT_EXIST; // account doesn't exist
+ }
if (utf8length(newEmail) > MAX_EMAIL_STR)
+ {
+ sScriptMgr->OnFailedEmailChange(accountId);
return AOR_EMAIL_TOO_LONG;
+ }
normalizeString(username);
normalizeString(newEmail);
@@ -212,6 +226,7 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail)
LoginDatabase.Execute(stmt);
+ sScriptMgr->OnEmailChange(accountId);
return AOR_OK;
}
@@ -220,10 +235,16 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai
std::string username;
if (!GetName(accountId, username))
+ {
+ sScriptMgr->OnFailedEmailChange(accountId);
return AOR_NAME_NOT_EXIST; // account doesn't exist
+ }
if (utf8length(newEmail) > MAX_EMAIL_STR)
+ {
+ sScriptMgr->OnFailedEmailChange(accountId);
return AOR_EMAIL_TOO_LONG;
+ }
normalizeString(username);
normalizeString(newEmail);
@@ -235,6 +256,7 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai
LoginDatabase.Execute(stmt);
+ sScriptMgr->OnEmailChange(accountId);
return AOR_OK;
}
diff --git a/src/server/game/Battlegrounds/ArenaScore.h b/src/server/game/Battlegrounds/ArenaScore.h
new file mode 100644
index 00000000000..7b25427c078
--- /dev/null
+++ b/src/server/game/Battlegrounds/ArenaScore.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 TRINITY_ARENA_SCORE_H
+#define TRINITY_ARENA_SCORE_H
+
+#include "BattlegroundScore.h"
+#include "SharedDefines.h"
+
+struct ArenaScore : public BattlegroundScore
+{
+ friend class BattlegroundBE;
+ friend class BattlegroundDS;
+ friend class BattlegroundNA;
+ friend class BattlegroundRL;
+ friend class BattlegroundRV;
+
+ protected:
+ ArenaScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid), TeamId(team == ALLIANCE ? 1 : 0) { }
+
+ void AppendToPacket(WorldPacket& data) final
+ {
+ data << uint64(PlayerGuid);
+
+ data << uint32(KillingBlows);
+ data << uint8(TeamId);
+ data << uint32(DamageDone);
+ data << uint32(HealingDone);
+ data << uint32(0); // Objectives Count
+ }
+
+ // For Logging purpose
+ std::string ToString() const override
+ {
+ std::ostringstream stream;
+ stream << "Damage done: " << DamageDone << ", Healing done: " << HealingDone << ", Killing blows: " << KillingBlows;
+ return stream.str();
+ }
+
+ uint8 TeamId; // TEAM_ALLIANCE or TEAM_HORDE
+};
+
+struct ArenaTeamScore
+{
+ friend class Battleground;
+
+ protected:
+ ArenaTeamScore() : RatingChange(0), MatchmakerRating(0) { }
+
+ virtual ~ArenaTeamScore() { }
+
+ void Assign(int32 ratingChange, uint32 matchMakerRating, std::string const& teamName)
+ {
+ RatingChange = ratingChange;
+ MatchmakerRating = matchMakerRating;
+ TeamName = teamName;
+ }
+
+ void BuildRatingInfoBlock(WorldPacket& data)
+ {
+ uint32 ratingLost = std::abs(std::min(RatingChange, 0));
+ uint32 ratingWon = std::max(RatingChange, 0);
+
+ data << uint32(ratingLost);
+ data << uint32(ratingWon);
+ data << uint32(MatchmakerRating);
+ }
+
+ void BuildTeamInfoBlock(WorldPacket& data)
+ {
+ data << TeamName;
+ }
+
+ int32 RatingChange;
+ uint32 MatchmakerRating;
+ std::string TeamName;
+};
+
+#endif // TRINITY_ARENA_SCORE_H
diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h
index cd9e2be4318..c977a137c2a 100644
--- a/src/server/game/Battlegrounds/ArenaTeam.h
+++ b/src/server/game/Battlegrounds/ArenaTeam.h
@@ -130,7 +130,7 @@ class ArenaTeam
uint8 GetSlot() const { return GetSlotByType(GetType()); }
static uint8 GetSlotByType(uint32 type);
uint64 GetCaptain() const { return CaptainGuid; }
- std::string const& GetName() const { return TeamName; }
+ std::string const& GetName() const { return TeamName; }
const ArenaTeamStats& GetStats() const { return Stats; }
uint32 GetRating() const { return Stats.Rating; }
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index ca48ffb3a14..fd3e13cf583 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -16,10 +16,12 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "ArenaScore.h"
#include "ArenaTeam.h"
#include "ArenaTeamMgr.h"
#include "Battleground.h"
#include "BattlegroundMgr.h"
+#include "BattlegroundScore.h"
#include "Creature.h"
#include "CreatureTextMgr.h"
#include "Chat.h"
@@ -165,12 +167,13 @@ Battleground::Battleground()
m_ArenaTeamIds[TEAM_ALLIANCE] = 0;
m_ArenaTeamIds[TEAM_HORDE] = 0;
- m_ArenaTeamRatingChanges[TEAM_ALLIANCE] = 0;
- m_ArenaTeamRatingChanges[TEAM_HORDE] = 0;
-
m_ArenaTeamMMR[TEAM_ALLIANCE] = 0;
m_ArenaTeamMMR[TEAM_HORDE] = 0;
+ // Iterate this way for consistency's sake - client expects it to be sent in this order
+ for (int8 i = WINNER_ALLIANCE; i >= WINNER_HORDE; --i)
+ _arenaTeamScores[i] = new ArenaTeamScore();
+
m_BgRaids[TEAM_ALLIANCE] = NULL;
m_BgRaids[TEAM_HORDE] = NULL;
@@ -222,6 +225,10 @@ Battleground::~Battleground()
for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
delete itr->second;
+
+ // Iterate this way for consistency's sake - client expects it to be sent in this order
+ for (int8 i = WINNER_ALLIANCE; i >= WINNER_HORDE; --i)
+ delete _arenaTeamScores[i];
}
void Battleground::Update(uint32 diff)
@@ -771,49 +778,50 @@ void Battleground::EndBattleground(uint32 winner)
if (winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam)
{
+ loserTeamRating = loserArenaTeam->GetRating();
+ loserMatchmakerRating = GetArenaMatchmakerRating(GetOtherTeam(winner));
+ winnerTeamRating = winnerArenaTeam->GetRating();
+ winnerMatchmakerRating = GetArenaMatchmakerRating(winner);
+
if (winner != WINNER_NONE)
{
- loserTeamRating = loserArenaTeam->GetRating();
- loserMatchmakerRating = GetArenaMatchmakerRating(GetOtherTeam(winner));
- winnerTeamRating = winnerArenaTeam->GetRating();
- winnerMatchmakerRating = GetArenaMatchmakerRating(winner);
winnerMatchmakerChange = winnerArenaTeam->WonAgainst(winnerMatchmakerRating, loserMatchmakerRating, winnerChange);
loserMatchmakerChange = loserArenaTeam->LostAgainst(loserMatchmakerRating, winnerMatchmakerRating, loserChange);
TC_LOG_DEBUG("bg.arena", "match Type: %u --- Winner: old rating: %u, rating gain: %d, old MMR: %u, MMR gain: %d --- Loser: old rating: %u, rating loss: %d, old MMR: %u, MMR loss: %d ---", m_ArenaType, winnerTeamRating, winnerChange, winnerMatchmakerRating,
winnerMatchmakerChange, loserTeamRating, loserChange, loserMatchmakerRating, loserMatchmakerChange);
SetArenaMatchmakerRating(winner, winnerMatchmakerRating + winnerMatchmakerChange);
SetArenaMatchmakerRating(GetOtherTeam(winner), loserMatchmakerRating + loserMatchmakerChange);
- SetArenaTeamRatingChangeForTeam(winner, winnerChange);
- SetArenaTeamRatingChangeForTeam(GetOtherTeam(winner), loserChange);
+
+ uint8 winnerId = GetWinner();
+ uint8 loserId = winnerId == WINNER_ALLIANCE ? uint8(WINNER_HORDE) : winnerId;
+
+ _arenaTeamScores[winnerId]->Assign(winnerChange, winnerMatchmakerRating + winnerMatchmakerChange, winnerArenaTeam->GetName());
+ _arenaTeamScores[loserId]->Assign(loserChange, loserMatchmakerRating + loserMatchmakerChange, loserArenaTeam->GetName());
+
TC_LOG_DEBUG("bg.arena", "Arena match Type: %u for Team1Id: %u - Team2Id: %u ended. WinnerTeamId: %u. Winner rating: +%d, Loser rating: %d", m_ArenaType, m_ArenaTeamIds[TEAM_ALLIANCE], m_ArenaTeamIds[TEAM_HORDE], winnerArenaTeam->GetId(), winnerChange, loserChange);
if (sWorld->getBoolConfig(CONFIG_ARENA_LOG_EXTENDED_INFO))
- for (Battleground::BattlegroundScoreMap::const_iterator itr = GetPlayerScoresBegin(); itr != GetPlayerScoresEnd(); ++itr)
- if (Player* player = ObjectAccessor::FindPlayer(itr->first))
+ for (auto const& score : PlayerScores)
+ if (Player* player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(score.first, 0, HIGHGUID_PLAYER)))
{
- TC_LOG_DEBUG("bg.arena", "Statistics match Type: %u for %s (GUID: " UI64FMTD ", Team: %d, IP: %s): %u damage, %u healing, %u killing blows",
- m_ArenaType, player->GetName().c_str(), itr->first, player->GetArenaTeamId(m_ArenaType == 5 ? 2 : m_ArenaType == 3),
- player->GetSession()->GetRemoteAddress().c_str(), itr->second->DamageDone, itr->second->HealingDone,
- itr->second->KillingBlows);
+ TC_LOG_DEBUG("bg.arena", "Statistics match Type: %u for %s (GUID: %u, Team: %d, IP: %s): %s",
+ m_ArenaType, player->GetName().c_str(), score.first, player->GetArenaTeamId(m_ArenaType == 5 ? 2 : m_ArenaType == 3),
+ player->GetSession()->GetRemoteAddress().c_str(), score.second->ToString().c_str());
}
}
// Deduct 16 points from each teams arena-rating if there are no winners after 45+2 minutes
else
{
- SetArenaTeamRatingChangeForTeam(ALLIANCE, ARENA_TIMELIMIT_POINTS_LOSS);
- SetArenaTeamRatingChangeForTeam(HORDE, ARENA_TIMELIMIT_POINTS_LOSS);
+ _arenaTeamScores[WINNER_ALLIANCE]->Assign(ARENA_TIMELIMIT_POINTS_LOSS, winnerMatchmakerRating + winnerMatchmakerChange, winnerArenaTeam->GetName());
+ _arenaTeamScores[WINNER_HORDE]->Assign(ARENA_TIMELIMIT_POINTS_LOSS, loserMatchmakerRating + loserMatchmakerChange, loserArenaTeam->GetName());
+
winnerArenaTeam->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS);
loserArenaTeam->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS);
}
}
- else
- {
- SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
- SetArenaTeamRatingChangeForTeam(HORDE, 0);
- }
}
WorldPacket pvpLogData;
- sBattlegroundMgr->BuildPvpLogDataPacket(&pvpLogData, this);
+ BuildPvPLogDataPacket(pvpLogData);
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
@@ -958,7 +966,7 @@ void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
participant = true;
}
- BattlegroundScoreMap::iterator itr2 = PlayerScores.find(guid);
+ BattlegroundScoreMap::iterator itr2 = PlayerScores.find(GUID_LOPART(guid));
if (itr2 != PlayerScores.end())
{
delete itr2->second; // delete player's score
@@ -1349,47 +1357,48 @@ bool Battleground::HasFreeSlots() const
return GetPlayersSize() < GetMaxPlayers();
}
-void Battleground::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor)
+void Battleground::BuildPvPLogDataPacket(WorldPacket& data)
{
- //this procedure is called from virtual function implemented in bg subclass
- BattlegroundScoreMap::const_iterator itr = PlayerScores.find(Source->GetGUID());
- if (itr == PlayerScores.end()) // player not found...
- return;
+ uint8 type = (isArena() ? 1 : 0);
+
+ data.Initialize(MSG_PVP_LOG_DATA, 1 + 1 + 4 + 40 * GetPlayerScoresSize());
+ data << uint8(type); // type (battleground = 0 / arena = 1)
- switch (type)
+ if (type) // arena
{
- case SCORE_KILLING_BLOWS: // Killing blows
- itr->second->KillingBlows += value;
- break;
- case SCORE_DEATHS: // Deaths
- itr->second->Deaths += value;
- break;
- case SCORE_HONORABLE_KILLS: // Honorable kills
- itr->second->HonorableKills += value;
- break;
- case SCORE_BONUS_HONOR: // Honor bonus
- // do not add honor in arenas
- if (isBattleground())
- {
- // reward honor instantly
- if (doAddHonor)
- Source->RewardHonor(NULL, 1, value); // RewardHonor calls UpdatePlayerScore with doAddHonor = false
- else
- itr->second->BonusHonor += value;
- }
- break;
- // used only in EY, but in MSG_PVP_LOG_DATA opcode
- case SCORE_DAMAGE_DONE: // Damage Done
- itr->second->DamageDone += value;
- break;
- case SCORE_HEALING_DONE: // Healing Done
- itr->second->HealingDone += value;
- break;
- default:
- TC_LOG_ERROR("bg.battleground", "Battleground::UpdatePlayerScore: unknown score type (%u) for BG (map: %u, instance id: %u)!",
- type, m_MapId, m_InstanceID);
- break;
+ // it seems this must be according to BG_WINNER_A/H and _NOT_ TEAM_A/H
+ for (int8 i = WINNER_ALLIANCE; i >= WINNER_HORDE; --i)
+ _arenaTeamScores[i]->BuildRatingInfoBlock(data);
+
+ for (int8 i = WINNER_ALLIANCE; i >= WINNER_HORDE; --i)
+ _arenaTeamScores[i]->BuildTeamInfoBlock(data);
}
+
+ if (GetStatus() == STATUS_WAIT_LEAVE)
+ {
+ data << uint8(1); // bg ended
+ data << uint8(GetWinner()); // who win
+ }
+ else
+ data << uint8(0); // bg not ended
+
+ data << uint32(GetPlayerScoresSize());
+ for (auto const& score : PlayerScores)
+ score.second->AppendToPacket(data);
+}
+
+bool Battleground::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
+{
+ BattlegroundScoreMap::const_iterator itr = PlayerScores.find(player->GetGUIDLow());
+ if (itr == PlayerScores.end()) // player not found...
+ return false;
+
+ itr->second->UpdateScore(type, value);
+
+ if (type == SCORE_BONUS_HONOR && doAddHonor && isBattleground())
+ player->RewardHonor(NULL, 1, value); // RewardHonor calls UpdatePlayerScore with doAddHonor = false
+
+ return true;
}
void Battleground::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
@@ -1868,7 +1877,7 @@ void Battleground::PlayerAddedToBGCheckIfBGIsRunning(Player* player)
BlockMovement(player);
- sBattlegroundMgr->BuildPvpLogDataPacket(&data, this);
+ BuildPvPLogDataPacket(data);
player->SendDirectMessage(&data);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBGTeam());
diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h
index 4256e2fc094..7d1bf550695 100644
--- a/src/server/game/Battlegrounds/Battleground.h
+++ b/src/server/game/Battlegrounds/Battleground.h
@@ -32,6 +32,8 @@ class WorldObject;
class WorldPacket;
class BattlegroundMap;
+struct ArenaTeamScore;
+struct BattlegroundScore;
struct Position;
struct PvPDifficultyEntry;
struct WorldSafeLocsEntry;
@@ -171,34 +173,6 @@ struct BattlegroundObjectInfo
uint32 spellid;
};
-enum ScoreType
-{
- SCORE_KILLING_BLOWS = 1,
- SCORE_DEATHS = 2,
- SCORE_HONORABLE_KILLS = 3,
- SCORE_BONUS_HONOR = 4,
- //EY, but in MSG_PVP_LOG_DATA opcode!
- SCORE_DAMAGE_DONE = 5,
- SCORE_HEALING_DONE = 6,
- //WS
- SCORE_FLAG_CAPTURES = 7,
- SCORE_FLAG_RETURNS = 8,
- //AB and IC
- SCORE_BASES_ASSAULTED = 9,
- SCORE_BASES_DEFENDED = 10,
- //AV
- SCORE_GRAVEYARDS_ASSAULTED = 11,
- SCORE_GRAVEYARDS_DEFENDED = 12,
- SCORE_TOWERS_ASSAULTED = 13,
- SCORE_TOWERS_DEFENDED = 14,
- SCORE_MINES_CAPTURED = 15,
- SCORE_LEADERS_KILLED = 16,
- SCORE_SECONDARY_OBJECTIVES = 17,
- //SOTA
- SCORE_DESTROYED_DEMOLISHER = 18,
- SCORE_DESTROYED_WALL = 19
-};
-
enum ArenaType
{
ARENA_TYPE_2v2 = 2,
@@ -239,22 +213,6 @@ enum BattlegroundStartingEventsIds
};
#define BG_STARTING_EVENT_COUNT 4
-struct BattlegroundScore
-{
- BattlegroundScore() : KillingBlows(0), Deaths(0), HonorableKills(0), BonusHonor(0),
- DamageDone(0), HealingDone(0)
- { }
-
- virtual ~BattlegroundScore() { } //virtual destructor is used when deleting score from scores map
-
- uint32 KillingBlows;
- uint32 Deaths;
- uint32 HonorableKills;
- uint32 BonusHonor;
- uint32 DamageDone;
- uint32 HealingDone;
-};
-
enum BGHonorMode
{
BG_NORMAL = 0,
@@ -369,9 +327,7 @@ class Battleground
BattlegroundPlayerMap const& GetPlayers() const { return m_Players; }
uint32 GetPlayersSize() const { return m_Players.size(); }
- typedef std::map<uint64, BattlegroundScore*> BattlegroundScoreMap;
- BattlegroundScoreMap::const_iterator GetPlayerScoresBegin() const { return PlayerScores.begin(); }
- BattlegroundScoreMap::const_iterator GetPlayerScoresEnd() const { return PlayerScores.end(); }
+ typedef std::map<uint32, BattlegroundScore*> BattlegroundScoreMap;
uint32 GetPlayerScoresSize() const { return PlayerScores.size(); }
uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); }
@@ -443,7 +399,8 @@ class Battleground
Group* GetBgRaid(uint32 TeamID) const { return TeamID == ALLIANCE ? m_BgRaids[TEAM_ALLIANCE] : m_BgRaids[TEAM_HORDE]; }
void SetBgRaid(uint32 TeamID, Group* bg_raid);
- virtual void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
+ void BuildPvPLogDataPacket(WorldPacket& data);
+ virtual bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
static TeamId GetTeamIndexByTeamId(uint32 Team) { return Team == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE; }
uint32 GetPlayersCountByTeam(uint32 Team) const { return m_PlayersCount[GetTeamIndexByTeamId(Team)]; }
@@ -460,12 +417,8 @@ class Battleground
void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId) { m_ArenaTeamIds[GetTeamIndexByTeamId(Team)] = ArenaTeamId; }
uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[GetTeamIndexByTeamId(Team)]; }
uint32 GetArenaTeamIdByIndex(uint32 index) const { return m_ArenaTeamIds[index]; }
- void SetArenaTeamRatingChangeForTeam(uint32 Team, int32 RatingChange) { m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)] = RatingChange; }
- int32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)]; }
- int32 GetArenaTeamRatingChangeByIndex(uint32 index) const { return m_ArenaTeamRatingChanges[index]; }
void SetArenaMatchmakerRating(uint32 Team, uint32 MMR){ m_ArenaTeamMMR[GetTeamIndexByTeamId(Team)] = MMR; }
uint32 GetArenaMatchmakerRating(uint32 Team) const { return m_ArenaTeamMMR[GetTeamIndexByTeamId(Team)]; }
- uint32 GetArenaMatchmakerRatingByIndex(uint32 index) const { return m_ArenaTeamMMR[index]; }
void CheckArenaAfterTimerConditions();
void CheckArenaWinConditions();
void UpdateArenaWorldState();
@@ -657,8 +610,8 @@ class Battleground
// Arena team ids by team
uint32 m_ArenaTeamIds[BG_TEAMS_COUNT];
- int32 m_ArenaTeamRatingChanges[BG_TEAMS_COUNT];
uint32 m_ArenaTeamMMR[BG_TEAMS_COUNT];
+ ArenaTeamScore* _arenaTeamScores[BG_TEAMS_COUNT];
// Limits
uint32 m_LevelMin;
diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
index ab69c950ff4..ef78594626a 100644
--- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
@@ -216,176 +216,6 @@ void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battlegro
}
}
-void BattlegroundMgr::BuildPvpLogDataPacket(WorldPacket* data, Battleground* bg)
-{
- uint8 type = (bg->isArena() ? 1 : 0);
-
- data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
- *data << uint8(type); // type (battleground=0/arena=1)
-
- if (type) // arena
- {
- // it seems this must be according to BG_WINNER_A/H and _NOT_ TEAM_A/H
- for (int8 i = 1; i >= 0; --i)
- {
- int32 rating_change = bg->GetArenaTeamRatingChangeByIndex(i);
-
- uint32 pointsLost = rating_change < 0 ? -rating_change : 0;
- uint32 pointsGained = rating_change > 0 ? rating_change : 0;
- uint32 MatchmakerRating = bg->GetArenaMatchmakerRatingByIndex(i);
-
- *data << uint32(pointsLost); // Rating Lost
- *data << uint32(pointsGained); // Rating gained
- *data << uint32(MatchmakerRating); // Matchmaking Value
- TC_LOG_DEBUG("bg.battleground", "rating change: %d", rating_change);
- }
- for (int8 i = 1; i >= 0; --i)
- {
- if (ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(bg->GetArenaTeamIdByIndex(i)))
- *data << at->GetName();
- else
- *data << uint8(0);
- }
- }
-
- if (bg->GetStatus() != STATUS_WAIT_LEAVE)
- *data << uint8(0); // bg not ended
- else
- {
- *data << uint8(1); // bg ended
- *data << uint8(bg->GetWinner()); // who win
- }
-
- size_t wpos = data->wpos();
- uint32 scoreCount = 0;
- *data << uint32(scoreCount); // placeholder
-
- Battleground::BattlegroundScoreMap::const_iterator itr2 = bg->GetPlayerScoresBegin();
- for (Battleground::BattlegroundScoreMap::const_iterator itr = itr2; itr != bg->GetPlayerScoresEnd();)
- {
- itr2 = itr++;
- BattlegroundScore* score = itr2->second;
- if (!bg->IsPlayerInBattleground(itr2->first))
- {
- TC_LOG_ERROR("bg.battleground", "Player " UI64FMTD " has scoreboard entry for battleground %u but is not in battleground!", itr->first, bg->GetTypeID(true));
- continue;
- }
-
- *data << uint64(itr2->first);
- *data << uint32(score->KillingBlows);
- if (type == 0)
- {
- *data << uint32(score->HonorableKills);
- *data << uint32(score->Deaths);
- *data << uint32(score->BonusHonor);
- }
- else
- {
- Player* player = ObjectAccessor::FindPlayer(itr2->first);
- uint32 team = bg->GetPlayerTeam(itr2->first);
- if (!team && player)
- team = player->GetBGTeam();
- *data << uint8(team == ALLIANCE ? 1 : 0); // green or yellow
- }
- *data << uint32(score->DamageDone); // damage done
- *data << uint32(score->HealingDone); // healing done
- switch (bg->GetTypeID(true)) // battleground specific things
- {
- case BATTLEGROUND_RB:
- switch (bg->GetMapId())
- {
- case 489:
- *data << uint32(0x00000002); // count of next fields
- *data << uint32(((BattlegroundWGScore*)score)->FlagCaptures); // flag captures
- *data << uint32(((BattlegroundWGScore*)score)->FlagReturns); // flag returns
- break;
- case 566:
- *data << uint32(0x00000001); // count of next fields
- *data << uint32(((BattlegroundEYScore*)score)->FlagCaptures); // flag captures
- break;
- case 529:
- *data << uint32(0x00000002); // count of next fields
- *data << uint32(((BattlegroundABScore*)score)->BasesAssaulted); // bases asssulted
- *data << uint32(((BattlegroundABScore*)score)->BasesDefended); // bases defended
- break;
- case 30:
- *data << uint32(0x00000005); // count of next fields
- *data << uint32(((BattlegroundAVScore*)score)->GraveyardsAssaulted); // GraveyardsAssaulted
- *data << uint32(((BattlegroundAVScore*)score)->GraveyardsDefended); // GraveyardsDefended
- *data << uint32(((BattlegroundAVScore*)score)->TowersAssaulted); // TowersAssaulted
- *data << uint32(((BattlegroundAVScore*)score)->TowersDefended); // TowersDefended
- *data << uint32(((BattlegroundAVScore*)score)->MinesCaptured); // MinesCaptured
- break;
- case 607:
- *data << uint32(0x00000002); // count of next fields
- *data << uint32(((BattlegroundSAScore*)score)->demolishers_destroyed);
- *data << uint32(((BattlegroundSAScore*)score)->gates_destroyed);
- break;
- case 628: // IC
- *data << uint32(0x00000002); // count of next fields
- *data << uint32(((BattlegroundICScore*)score)->BasesAssaulted); // bases asssulted
- *data << uint32(((BattlegroundICScore*)score)->BasesDefended); // bases defended
- default:
- *data << uint32(0);
- break;
- }
- break;
- case BATTLEGROUND_AV:
- *data << uint32(0x00000005); // count of next fields
- *data << uint32(((BattlegroundAVScore*)score)->GraveyardsAssaulted); // GraveyardsAssaulted
- *data << uint32(((BattlegroundAVScore*)score)->GraveyardsDefended); // GraveyardsDefended
- *data << uint32(((BattlegroundAVScore*)score)->TowersAssaulted); // TowersAssaulted
- *data << uint32(((BattlegroundAVScore*)score)->TowersDefended); // TowersDefended
- *data << uint32(((BattlegroundAVScore*)score)->MinesCaptured); // MinesCaptured
- break;
- case BATTLEGROUND_WS:
- *data << uint32(0x00000002); // count of next fields
- *data << uint32(((BattlegroundWGScore*)score)->FlagCaptures); // flag captures
- *data << uint32(((BattlegroundWGScore*)score)->FlagReturns); // flag returns
- break;
- case BATTLEGROUND_AB:
- *data << uint32(0x00000002); // count of next fields
- *data << uint32(((BattlegroundABScore*)score)->BasesAssaulted); // bases assaulted
- *data << uint32(((BattlegroundABScore*)score)->BasesDefended); // bases defended
- break;
- case BATTLEGROUND_EY:
- *data << uint32(0x00000001); // count of next fields
- *data << uint32(((BattlegroundEYScore*)score)->FlagCaptures); // flag captures
- break;
- case BATTLEGROUND_SA:
- *data << uint32(0x00000002); // count of next fields
- *data << uint32(((BattlegroundSAScore*)score)->demolishers_destroyed);
- *data << uint32(((BattlegroundSAScore*)score)->gates_destroyed);
- break;
- case BATTLEGROUND_IC:
- *data << uint32(0x00000002); // count of next fields
- *data << uint32(((BattlegroundICScore*)score)->BasesAssaulted); // bases assaulted
- *data << uint32(((BattlegroundICScore*)score)->BasesDefended); // bases defended
- break;
- case BATTLEGROUND_NA:
- case BATTLEGROUND_BE:
- case BATTLEGROUND_AA:
- case BATTLEGROUND_RL:
- case BATTLEGROUND_DS:
- case BATTLEGROUND_RV:
- *data << uint32(0);
- break;
- default:
- TC_LOG_DEBUG("network", "Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
- *data << uint32(0);
- break;
- }
- // should never happen
- if (++scoreCount >= bg->GetMaxPlayers() && itr != bg->GetPlayerScoresEnd())
- {
- TC_LOG_ERROR("bg.battleground", "Battleground %u scoreboard has more entries (%u) than allowed players in this bg (%u)", bg->GetTypeID(true), bg->GetPlayerScoresSize(), bg->GetMaxPlayers());
- break;
- }
- }
-
- data->put(wpos, scoreCount);
-}
-
void BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result)
{
data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h
index 786e664c3f3..b57efc045d8 100644
--- a/src/server/game/Battlegrounds/BattlegroundMgr.h
+++ b/src/server/game/Battlegrounds/BattlegroundMgr.h
@@ -79,7 +79,6 @@ class BattlegroundMgr
void BuildBattlegroundListPacket(WorldPacket* data, uint64 guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere);
void BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result);
void BuildUpdateWorldStatePacket(WorldPacket* data, uint32 field, uint32 value);
- void BuildPvpLogDataPacket(WorldPacket* data, Battleground* bg);
void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType, uint32 arenaFaction);
void BuildPlaySoundPacket(WorldPacket* data, uint32 soundId);
void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, uint64 guid);
diff --git a/src/server/game/Battlegrounds/BattlegroundScore.h b/src/server/game/Battlegrounds/BattlegroundScore.h
new file mode 100644
index 00000000000..7fedc4dbc4d
--- /dev/null
+++ b/src/server/game/Battlegrounds/BattlegroundScore.h
@@ -0,0 +1,120 @@
+/*
+ * 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 TRINITY_BATTLEGROUND_SCORE_H
+#define TRINITY_BATTLEGROUND_SCORE_H
+
+#include "WorldPacket.h"
+
+enum ScoreType
+{
+ SCORE_KILLING_BLOWS = 1,
+ SCORE_DEATHS = 2,
+ SCORE_HONORABLE_KILLS = 3,
+ SCORE_BONUS_HONOR = 4,
+ SCORE_DAMAGE_DONE = 5,
+ SCORE_HEALING_DONE = 6,
+
+ // WS and EY
+ SCORE_FLAG_CAPTURES = 7,
+ SCORE_FLAG_RETURNS = 8,
+
+ // AB and IC
+ SCORE_BASES_ASSAULTED = 9,
+ SCORE_BASES_DEFENDED = 10,
+
+ // AV
+ SCORE_GRAVEYARDS_ASSAULTED = 11,
+ SCORE_GRAVEYARDS_DEFENDED = 12,
+ SCORE_TOWERS_ASSAULTED = 13,
+ SCORE_TOWERS_DEFENDED = 14,
+ SCORE_MINES_CAPTURED = 15,
+
+ // SOTA
+ SCORE_DESTROYED_DEMOLISHER = 16,
+ SCORE_DESTROYED_WALL = 17
+};
+
+struct BattlegroundScore
+{
+ friend class Battleground;
+
+ protected:
+ BattlegroundScore(uint64 playerGuid) : PlayerGuid(playerGuid), KillingBlows(0), Deaths(0),
+ HonorableKills(0), BonusHonor(0), DamageDone(0), HealingDone(0) { }
+
+ virtual ~BattlegroundScore() { }
+
+ virtual void UpdateScore(uint32 type, uint32 value)
+ {
+ switch (type)
+ {
+ case SCORE_KILLING_BLOWS: // Killing blows
+ KillingBlows += value;
+ break;
+ case SCORE_DEATHS: // Deaths
+ Deaths += value;
+ break;
+ case SCORE_HONORABLE_KILLS: // Honorable kills
+ HonorableKills += value;
+ break;
+ case SCORE_BONUS_HONOR: // Honor bonus
+ BonusHonor += value;
+ break;
+ case SCORE_DAMAGE_DONE: // Damage Done
+ DamageDone += value;
+ break;
+ case SCORE_HEALING_DONE: // Healing Done
+ HealingDone += value;
+ break;
+ default:
+ ASSERT(false && "Not implemented Battleground score type!");
+ break;
+ }
+ }
+
+ virtual void AppendToPacket(WorldPacket& data)
+ {
+ data << uint64(PlayerGuid);
+
+ data << uint32(KillingBlows);
+ data << uint32(HonorableKills);
+ data << uint32(Deaths);
+ data << uint32(BonusHonor);
+ data << uint32(DamageDone);
+ data << uint32(HealingDone);
+
+ BuildObjectivesBlock(data);
+ }
+
+ virtual void BuildObjectivesBlock(WorldPacket& /*data*/) { }
+
+ // For Logging purpose
+ virtual std::string ToString() const { return ""; }
+
+ uint64 PlayerGuid;
+
+ // Default score, present in every type
+ uint32 KillingBlows;
+ uint32 Deaths;
+ uint32 HonorableKills;
+ uint32 BonusHonor;
+ uint32 DamageDone;
+ uint32 HealingDone;
+};
+
+#endif // TRINITY_BATTLEGROUND_SCORE_H
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
index 38b0e3e084b..2622ab9501f 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
@@ -224,15 +224,11 @@ void BattlegroundAB::StartingEventOpenDoors()
void BattlegroundAB::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- //create score and add it to map, default values are set in the constructor
- BattlegroundABScore* sc = new BattlegroundABScore;
-
- PlayerScores[player->GetGUID()] = sc;
+ PlayerScores[player->GetGUIDLow()] = new BattlegroundABScore(player->GetGUID());
}
void BattlegroundAB::RemovePlayer(Player* /*player*/, uint64 /*guid*/, uint32 /*team*/)
{
-
}
void BattlegroundAB::HandleAreaTrigger(Player* player, uint32 trigger)
@@ -696,26 +692,23 @@ WorldSafeLocsEntry const* BattlegroundAB::GetClosestGraveYard(Player* player)
return good_entry;
}
-void BattlegroundAB::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor)
+bool BattlegroundAB::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{
- BattlegroundScoreMap::iterator itr = PlayerScores.find(Source->GetGUID());
- if (itr == PlayerScores.end()) // player not found...
- return;
+ if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor))
+ return false;
switch (type)
{
case SCORE_BASES_ASSAULTED:
- ((BattlegroundABScore*)itr->second)->BasesAssaulted += value;
- Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_ASSAULT_BASE);
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_ASSAULT_BASE);
break;
case SCORE_BASES_DEFENDED:
- ((BattlegroundABScore*)itr->second)->BasesDefended += value;
- Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_DEFEND_BASE);
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_DEFEND_BASE);
break;
default:
- Battleground::UpdatePlayerScore(Source, type, value, doAddHonor);
break;
}
+ return true;
}
bool BattlegroundAB::IsAllNodesControlledByTeam(uint32 team) const
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h
index 9abc7627b24..a6b4be10fdf 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h
@@ -20,6 +20,7 @@
#define __BATTLEGROUNDAB_H
#include "Battleground.h"
+#include "BattlegroundScore.h"
#include "Object.h"
enum BG_AB_WorldStates
@@ -236,12 +237,38 @@ struct BG_AB_BannerTimer
uint8 teamIndex;
};
-struct BattlegroundABScore : public BattlegroundScore
+struct BattlegroundABScore final : public BattlegroundScore
{
- BattlegroundABScore(): BasesAssaulted(0), BasesDefended(0) { }
- ~BattlegroundABScore() { }
- uint32 BasesAssaulted;
- uint32 BasesDefended;
+ friend class BattlegroundAB;
+
+ protected:
+ BattlegroundABScore(uint64 playerGuid) : BattlegroundScore(playerGuid), BasesAssaulted(0), BasesDefended(0) { }
+
+ void UpdateScore(uint32 type, uint32 value) override
+ {
+ switch (type)
+ {
+ case SCORE_BASES_ASSAULTED:
+ BasesAssaulted += value;
+ break;
+ case SCORE_BASES_DEFENDED:
+ BasesDefended += value;
+ break;
+ default:
+ BattlegroundScore::UpdateScore(type, value);
+ break;
+ }
+ }
+
+ void BuildObjectivesBlock(WorldPacket& data) final
+ {
+ data << uint32(2);
+ data << uint32(BasesAssaulted);
+ data << uint32(BasesDefended);
+ }
+
+ uint32 BasesAssaulted;
+ uint32 BasesDefended;
};
class BattlegroundAB : public Battleground
@@ -261,7 +288,7 @@ class BattlegroundAB : public Battleground
WorldSafeLocsEntry const* GetClosestGraveYard(Player* player);
/* Scorekeeping */
- void UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor = true);
+ bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
void FillInitialWorldStates(WorldPacket& data);
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
index 16576aa888e..eafb02f031d 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
@@ -47,7 +47,6 @@ BattlegroundAV::BattlegroundAV()
}
m_Mine_Timer = 0;
- m_MaxLevel = 0;
for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i)
InitNode(i, 0, false);
@@ -60,11 +59,6 @@ BattlegroundAV::BattlegroundAV()
BattlegroundAV::~BattlegroundAV() { }
-uint16 BattlegroundAV::GetBonusHonor(uint8 kills) /// @todo move this function to Battleground.cpp (needs to find a way to get m_MaxLevel)
-{
- return Trinity::Honor::hk_honor_at_level(m_MaxLevel, kills);
-}
-
void BattlegroundAV::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
@@ -95,7 +89,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer)
{
CastSpellOnTeam(23658, HORDE); //this is a spell which finishes a quest where a player has to kill the boss
RewardReputationToTeam(729, BG_AV_REP_BOSS, HORDE);
- RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS), HORDE);
+ RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_BOSS), HORDE);
EndBattleground(HORDE);
DelCreature(AV_CPLACE_TRIGGER17);
}
@@ -103,7 +97,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer)
{
CastSpellOnTeam(23658, ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss
RewardReputationToTeam(730, BG_AV_REP_BOSS, ALLIANCE);
- RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS), ALLIANCE);
+ RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_BOSS), ALLIANCE);
EndBattleground(ALLIANCE);
DelCreature(AV_CPLACE_TRIGGER19);
}
@@ -116,7 +110,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer)
}
m_CaptainAlive[0]=false;
RewardReputationToTeam(729, BG_AV_REP_CAPTAIN, HORDE);
- RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN), HORDE);
+ RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), HORDE);
UpdateScore(ALLIANCE, (-1)*BG_AV_RES_CAPTAIN);
//spawn destroyed aura
for (uint8 i=0; i <= 9; i++)
@@ -135,7 +129,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer)
}
m_CaptainAlive[1]=false;
RewardReputationToTeam(730, BG_AV_REP_CAPTAIN, ALLIANCE);
- RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN), ALLIANCE);
+ RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), ALLIANCE);
UpdateScore(HORDE, (-1)*BG_AV_RES_CAPTAIN);
//spawn destroyed aura
for (uint8 i=0; i <= 9; i++)
@@ -279,33 +273,24 @@ void BattlegroundAV::UpdateScore(uint16 team, int16 points)
Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type)
{
- uint8 level;
bool isStatic = false;
Creature* creature = NULL;
ASSERT(type <= AV_CPLACE_MAX + AV_STATICCPLACE_MAX);
if (type >= AV_CPLACE_MAX) //static
{
type -= AV_CPLACE_MAX;
- cinfoid=uint16(BG_AV_StaticCreaturePos[type][4]);
- creature = AddCreature(BG_AV_StaticCreatureInfo[cinfoid][0],
- (type+AV_CPLACE_MAX),
+ cinfoid = uint16(BG_AV_StaticCreaturePos[type][4]);
+ creature = AddCreature(BG_AV_StaticCreatureInfo[cinfoid],
+ type + AV_CPLACE_MAX,
BG_AV_StaticCreaturePos[type][0],
BG_AV_StaticCreaturePos[type][1],
BG_AV_StaticCreaturePos[type][2],
BG_AV_StaticCreaturePos[type][3]);
- level = (BG_AV_StaticCreatureInfo[cinfoid][2] == BG_AV_StaticCreatureInfo[cinfoid][3])
- ? BG_AV_StaticCreatureInfo[cinfoid][2]
- : urand(BG_AV_StaticCreatureInfo[cinfoid][2], BG_AV_StaticCreatureInfo[cinfoid][3]);
isStatic = true;
}
else
{
- creature = AddCreature(BG_AV_CreatureInfo[cinfoid][0],
- type,
- BG_AV_CreaturePos[type]);
- level = (BG_AV_CreatureInfo[cinfoid][2] == BG_AV_CreatureInfo[cinfoid][3])
- ? BG_AV_CreatureInfo[cinfoid][2]
- : urand(BG_AV_CreatureInfo[cinfoid][2], BG_AV_CreatureInfo[cinfoid][3]);
+ creature = AddCreature(BG_AV_CreatureInfo[cinfoid][0], type, BG_AV_CreaturePos[type]);
}
if (!creature)
return NULL;
@@ -330,10 +315,6 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type)
//just copied this code from a gm-command
}
- if (level != 0)
- level += m_MaxLevel - 60; //maybe we can do this more generic for custom level-range.. actually it's blizzlike
- creature->SetLevel(level);
-
uint32 triggerSpawnID = 0;
uint32 newFaction = 0;
if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0])
@@ -358,9 +339,7 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type)
}
if (triggerSpawnID && newFaction)
{
- if (Creature* trigger = AddCreature(WORLD_TRIGGER,
- triggerSpawnID,
- BG_AV_CreaturePos[triggerSpawnID]))
+ if (Creature* trigger = AddCreature(WORLD_TRIGGER, triggerSpawnID, BG_AV_CreaturePos[triggerSpawnID]))
{
trigger->setFaction(newFaction);
trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false);
@@ -459,11 +438,7 @@ void BattlegroundAV::StartingEventOpenDoors()
void BattlegroundAV::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- //create score and add it to map, default values are set in constructor
- BattlegroundAVScore* sc = new BattlegroundAVScore;
- PlayerScores[player->GetGUID()] = sc;
- if (m_MaxLevel == 0)
- m_MaxLevel=(player->getLevel()%10 == 0)? player->getLevel() : (player->getLevel()-(player->getLevel()%10))+10; /// @todo just look at the code \^_^/ --but queue-info should provide this information..
+ PlayerScores[player->GetGUIDLow()] = new BattlegroundAVScore(player->GetGUID());
}
void BattlegroundAV::EndBattleground(uint32 winner)
@@ -499,7 +474,7 @@ void BattlegroundAV::EndBattleground(uint32 winner)
if (rep[i] != 0)
RewardReputationToTeam(i == 0 ? 730 : 729, rep[i], i == 0 ? ALLIANCE : HORDE);
if (kills[i] != 0)
- RewardHonorToTeam(GetBonusHonor(kills[i]), i == 0 ? ALLIANCE : HORDE);
+ RewardHonorToTeam(GetBonusHonorFromKill(kills[i]), i == 0 ? ALLIANCE : HORDE);
}
/// @todo add enterevademode for all attacking creatures
@@ -553,43 +528,29 @@ void BattlegroundAV::HandleAreaTrigger(Player* player, uint32 trigger)
}
}
-void BattlegroundAV::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor)
+bool BattlegroundAV::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{
- BattlegroundScoreMap::iterator itr = PlayerScores.find(Source->GetGUID());
- if (itr == PlayerScores.end()) // player not found...
- return;
+ if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor))
+ return false;
switch (type)
{
case SCORE_GRAVEYARDS_ASSAULTED:
- ((BattlegroundAVScore*)itr->second)->GraveyardsAssaulted += value;
- Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_GRAVEYARD);
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_GRAVEYARD);
break;
case SCORE_GRAVEYARDS_DEFENDED:
- ((BattlegroundAVScore*)itr->second)->GraveyardsDefended += value;
- Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_GRAVEYARD);
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_GRAVEYARD);
break;
case SCORE_TOWERS_ASSAULTED:
- ((BattlegroundAVScore*)itr->second)->TowersAssaulted += value;
- Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_TOWER);
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_TOWER);
break;
case SCORE_TOWERS_DEFENDED:
- ((BattlegroundAVScore*)itr->second)->TowersDefended += value;
- Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_TOWER);
- break;
- case SCORE_MINES_CAPTURED:
- ((BattlegroundAVScore*)itr->second)->MinesCaptured += value;
- break;
- case SCORE_LEADERS_KILLED:
- ((BattlegroundAVScore*)itr->second)->LeadersKilled += value;
- break;
- case SCORE_SECONDARY_OBJECTIVES:
- ((BattlegroundAVScore*)itr->second)->SecondaryObjectives += value;
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_TOWER);
break;
default:
- Battleground::UpdatePlayerScore(Source, type, value, doAddHonor);
break;
}
+ return true;
}
void BattlegroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node)
@@ -617,7 +578,7 @@ void BattlegroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node)
UpdateScore((owner == ALLIANCE) ? HORDE : ALLIANCE, -1 * BG_AV_RES_TOWER);
RewardReputationToTeam(owner == ALLIANCE ? 730 : 729, BG_AV_REP_TOWER, owner);
- RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_TOWER), owner);
+ RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_TOWER), owner);
SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp), RESPAWN_ONE_DAY);
SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp), RESPAWN_ONE_DAY);
@@ -1222,27 +1183,27 @@ bool BattlegroundAV::SetupBattleground()
if (i <= BG_AV_NODES_FROSTWOLF_HUT)
{
if (!AddObject(i, BG_AV_OBJECTID_BANNER_A_B,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(i+11, BG_AV_OBJECTID_BANNER_CONT_A_B,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(i+33, BG_AV_OBJECTID_BANNER_H_B,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(i+22, BG_AV_OBJECTID_BANNER_CONT_H_B,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
//aura
|| !AddObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+i*3, BG_AV_OBJECTID_AURA_N,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+i*3, BG_AV_OBJECTID_AURA_A,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+i*3, BG_AV_OBJECTID_AURA_H,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY))
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!2");
return false;
@@ -1253,23 +1214,23 @@ bool BattlegroundAV::SetupBattleground()
if (i <= BG_AV_NODES_STONEHEART_BUNKER) //alliance towers
{
if (!AddObject(i, BG_AV_OBJECTID_BANNER_A,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(i+22, BG_AV_OBJECTID_BANNER_CONT_H,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_AURA_A,
- BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i+8],
+ 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_AURA_N,
- BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i+8],
+ 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_TOWER_BANNER_A,
- BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i+8],
+ 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_TOWER_BANNER_PH,
- BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY))
+ BG_AV_ObjectPos[i+8],
+ 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!3");
return false;
@@ -1278,23 +1239,23 @@ bool BattlegroundAV::SetupBattleground()
else //horde towers
{
if (!AddObject(i+7, BG_AV_OBJECTID_BANNER_CONT_A,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(i+29, BG_AV_OBJECTID_BANNER_H,
- BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i],
+ 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_AURA_N,
- BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i+8],
+ 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_AURA_H,
- BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i+8],
+ 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_TOWER_BANNER_PA,
- BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[i+8],
+ 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_TOWER_BANNER_H,
- BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3],
- 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY))
+ BG_AV_ObjectPos[i+8],
+ 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!4");
return false;
@@ -1304,14 +1265,11 @@ bool BattlegroundAV::SetupBattleground()
{
if (!AddObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j,
BG_AV_OBJECTID_FIRE,
- BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][0],
- BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][1],
- BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][2],
- BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3],
+ BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j],
0,
0,
- std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2),
- std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2),
+ std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j].GetOrientation()/2),
+ std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j].GetOrientation()/2),
RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!5.%i", i);
@@ -1328,14 +1286,11 @@ bool BattlegroundAV::SetupBattleground()
{
if (!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j,
BG_AV_OBJECTID_SMOKE,
- BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0],
- BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1],
- BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2],
- BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3],
+ BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j],
0,
0,
- std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),
- std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),
+ std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j].GetOrientation()/2),
+ std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j].GetOrientation()/2),
RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!6.%i", i);
@@ -1346,14 +1301,11 @@ bool BattlegroundAV::SetupBattleground()
{
if (!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j,
BG_AV_OBJECTID_FIRE,
- BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0],
- BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1],
- BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2],
- BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3],
+ BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j],
0,
0,
- std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),
- std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),
+ std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j].GetOrientation()/2),
+ std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j].GetOrientation()/2),
RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!7.%i", i);
@@ -1366,14 +1318,11 @@ bool BattlegroundAV::SetupBattleground()
{
if (!AddObject(BG_AV_OBJECT_MINE_SUPPLY_N_MIN+i,
BG_AV_OBJECTID_MINE_N,
- BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][0],
- BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][1],
- BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][2],
- BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3],
+ BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i],
0,
0,
- std::sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2),
- std::cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2),
+ std::sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i].GetOrientation()/2),
+ std::cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i].GetOrientation()/2),
RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some mine supplies Battleground not created!7.5.%i", i);
@@ -1384,14 +1333,11 @@ bool BattlegroundAV::SetupBattleground()
{
if (!AddObject(BG_AV_OBJECT_MINE_SUPPLY_S_MIN+i,
BG_AV_OBJECTID_MINE_S,
- BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][0],
- BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][1],
- BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][2],
- BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3],
+ BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i],
0,
0,
- std::sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2),
- std::cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2),
+ std::sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i].GetOrientation()/2),
+ std::cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i].GetOrientation()/2),
RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some mine supplies Battleground not created!7.6.%i", i);
@@ -1401,14 +1347,11 @@ bool BattlegroundAV::SetupBattleground()
if (!AddObject(BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE,
BG_AV_OBJECTID_BANNER_SNOWFALL_N,
- BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][0],
- BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][1],
- BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][2],
- BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3],
+ BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE],
0,
0,
- std::sin(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2),
- std::cos(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2),
+ std::sin(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE].GetOrientation()/2),
+ std::cos(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE].GetOrientation()/2),
RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!8");
@@ -1417,17 +1360,17 @@ bool BattlegroundAV::SetupBattleground()
for (uint8 i = 0; i < 4; i++)
{
if (!AddObject(BG_AV_OBJECT_SNOW_EYECANDY_A+i, BG_AV_OBJECTID_SNOWFALL_CANDY_A,
- BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i],
+ 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PA+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PA,
- BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i],
+ 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_H+i, BG_AV_OBJECTID_SNOWFALL_CANDY_H,
- BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY)
+ BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i],
+ 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PH+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PH,
- BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],
- 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY))
+ BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i],
+ 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), RESPAWN_ONE_DAY))
{
TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!9.%i", i);
return false;
@@ -1591,8 +1534,6 @@ void BattlegroundAV::DefendNode(BG_AV_Nodes node, uint16 team)
void BattlegroundAV::ResetBGSubclass()
{
- m_MaxLevel=0;
-
for (uint8 i=0; i<2; i++) //forloop for both teams (it just make 0 == alliance and 1 == horde also for both mines 0=north 1=south
{
for (uint8 j=0; j<9; j++)
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
index 03dd0ffcf5c..feb3c016e55 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
@@ -20,6 +20,7 @@
#define __BATTLEGROUNDAV_H
#include "Battleground.h"
+#include "BattlegroundScore.h"
#include "Object.h"
#define LANG_BG_AV_A_CAPTAIN_BUFF "Begone. Uncouth scum! The Alliance shall prevail in Alterac Valley!"
@@ -131,10 +132,10 @@ enum BG_AV_ObjectIds
BG_AV_OBJECTID_SNOWFALL_CANDY_PH = 179425,
//banners on top of towers:
- BG_AV_OBJECTID_TOWER_BANNER_A = 178927, //[PH] Alliance A1 Tower Banner BIG
- BG_AV_OBJECTID_TOWER_BANNER_H = 178955, //[PH] Horde H1 Tower Banner BIG
- BG_AV_OBJECTID_TOWER_BANNER_PA = 179446, //[PH] Alliance H1 Tower Pre-Banner BIG
- BG_AV_OBJECTID_TOWER_BANNER_PH = 179436, //[PH] Horde A1 Tower Pre-Banner BIG
+ BG_AV_OBJECTID_TOWER_BANNER_A = 178927, //[PH] Alliance A1 Tower Banner BIG
+ BG_AV_OBJECTID_TOWER_BANNER_H = 178955, //[PH] Horde H1 Tower Banner BIG
+ BG_AV_OBJECTID_TOWER_BANNER_PA = 179446, //[PH] Alliance H1 Tower Pre-Banner BIG
+ BG_AV_OBJECTID_TOWER_BANNER_PH = 179436, //[PH] Horde A1 Tower Pre-Banner BIG
//Auras
BG_AV_OBJECTID_AURA_A = 180421,
@@ -148,11 +149,11 @@ enum BG_AV_ObjectIds
BG_AV_OBJECTID_GATE_H = 180424,
//mine supplies
- BG_AV_OBJECTID_MINE_N = 178785,
- BG_AV_OBJECTID_MINE_S = 178784,
+ BG_AV_OBJECTID_MINE_N = 178785,
+ BG_AV_OBJECTID_MINE_S = 178784,
BG_AV_OBJECTID_FIRE = 179065,
- BG_AV_OBJECTID_SMOKE = 179066
+ BG_AV_OBJECTID_SMOKE = 179066
};
enum BG_AV_Nodes
@@ -306,58 +307,58 @@ enum BG_AV_ObjectTypes
BG_AV_OBJECT_MINE_SUPPLY_S_MIN = 225,
BG_AV_OBJECT_MINE_SUPPLY_S_MAX = 236,
- BG_AV_OBJECT_MAX = 237
+ BG_AV_OBJECT_MAX = 237
};
enum BG_AV_OBJECTS
{
- AV_OPLACE_FIRSTAID_STATION = 0,
- AV_OPLACE_STORMPIKE_GRAVE = 1,
- AV_OPLACE_STONEHEART_GRAVE = 2,
- AV_OPLACE_SNOWFALL_GRAVE = 3,
- AV_OPLACE_ICEBLOOD_GRAVE = 4,
- AV_OPLACE_FROSTWOLF_GRAVE = 5,
- AV_OPLACE_FROSTWOLF_HUT = 6,
- AV_OPLACE_DUNBALDAR_SOUTH = 7,
- AV_OPLACE_DUNBALDAR_NORTH = 8,
- AV_OPLACE_ICEWING_BUNKER = 9,
- AV_OPLACE_STONEHEART_BUNKER = 10,
- AV_OPLACE_ICEBLOOD_TOWER = 11,
- AV_OPLACE_TOWER_POINT = 12,
- AV_OPLACE_FROSTWOLF_ETOWER = 13,
- AV_OPLACE_FROSTWOLF_WTOWER = 14,
- AV_OPLACE_BIGBANNER_DUNBALDAR_SOUTH = 15,
- AV_OPLACE_BIGBANNER_DUNBALDAR_NORTH = 16,
- AV_OPLACE_BIGBANNER_ICEWING_BUNKER = 17,
- AV_OPLACE_BIGBANNER_STONEHEART_BUNKER = 18,
- AV_OPLACE_BIGBANNER_ICEBLOOD_TOWER = 19,
- AV_OPLACE_BIGBANNER_TOWER_POINT = 20,
- AV_OPLACE_BIGBANNER_FROSTWOLF_ETOWER = 21,
- AV_OPLACE_BIGBANNER_FROSTWOLF_WTOWER = 22,
-
- AV_OPLACE_BURN_DUNBALDAR_SOUTH = 23,
- AV_OPLACE_BURN_DUNBALDAR_NORTH = 33,
- AV_OPLACE_BURN_ICEWING_BUNKER = 43,
- AV_OPLACE_BURN_STONEHEART_BUNKER = 53,
- AV_OPLACE_BURN_ICEBLOOD_TOWER = 63,
- AV_OPLACE_BURN_TOWER_POINT = 73,
- AV_OPLACE_BURN_FROSTWOLF_ETOWER = 83,
- AV_OPLACE_BURN_FROSTWOLF_WTOWER = 93,
- AV_OPLACE_BURN_BUILDING_A = 103,
- AV_OPLACE_BURN_BUILDING_H = 113,
- AV_OPLACE_SNOW_1 = 123,
- AV_OPLACE_SNOW_2 = 124,
- AV_OPLACE_SNOW_3 = 125,
- AV_OPLACE_SNOW_4 = 126,
- AV_OPLACE_MINE_SUPPLY_N_MIN = 127,
- AV_OPLACE_MINE_SUPPLY_N_MAX = 136,
- AV_OPLACE_MINE_SUPPLY_S_MIN = 137,
- AV_OPLACE_MINE_SUPPLY_S_MAX = 148,
-
- AV_OPLACE_MAX = 149
+ AV_OPLACE_FIRSTAID_STATION = 0,
+ AV_OPLACE_STORMPIKE_GRAVE = 1,
+ AV_OPLACE_STONEHEART_GRAVE = 2,
+ AV_OPLACE_SNOWFALL_GRAVE = 3,
+ AV_OPLACE_ICEBLOOD_GRAVE = 4,
+ AV_OPLACE_FROSTWOLF_GRAVE = 5,
+ AV_OPLACE_FROSTWOLF_HUT = 6,
+ AV_OPLACE_DUNBALDAR_SOUTH = 7,
+ AV_OPLACE_DUNBALDAR_NORTH = 8,
+ AV_OPLACE_ICEWING_BUNKER = 9,
+ AV_OPLACE_STONEHEART_BUNKER = 10,
+ AV_OPLACE_ICEBLOOD_TOWER = 11,
+ AV_OPLACE_TOWER_POINT = 12,
+ AV_OPLACE_FROSTWOLF_ETOWER = 13,
+ AV_OPLACE_FROSTWOLF_WTOWER = 14,
+ AV_OPLACE_BIGBANNER_DUNBALDAR_SOUTH = 15,
+ AV_OPLACE_BIGBANNER_DUNBALDAR_NORTH = 16,
+ AV_OPLACE_BIGBANNER_ICEWING_BUNKER = 17,
+ AV_OPLACE_BIGBANNER_STONEHEART_BUNKER = 18,
+ AV_OPLACE_BIGBANNER_ICEBLOOD_TOWER = 19,
+ AV_OPLACE_BIGBANNER_TOWER_POINT = 20,
+ AV_OPLACE_BIGBANNER_FROSTWOLF_ETOWER = 21,
+ AV_OPLACE_BIGBANNER_FROSTWOLF_WTOWER = 22,
+
+ AV_OPLACE_BURN_DUNBALDAR_SOUTH = 23,
+ AV_OPLACE_BURN_DUNBALDAR_NORTH = 33,
+ AV_OPLACE_BURN_ICEWING_BUNKER = 43,
+ AV_OPLACE_BURN_STONEHEART_BUNKER = 53,
+ AV_OPLACE_BURN_ICEBLOOD_TOWER = 63,
+ AV_OPLACE_BURN_TOWER_POINT = 73,
+ AV_OPLACE_BURN_FROSTWOLF_ETOWER = 83,
+ AV_OPLACE_BURN_FROSTWOLF_WTOWER = 93,
+ AV_OPLACE_BURN_BUILDING_A = 103,
+ AV_OPLACE_BURN_BUILDING_H = 113,
+ AV_OPLACE_SNOW_1 = 123,
+ AV_OPLACE_SNOW_2 = 124,
+ AV_OPLACE_SNOW_3 = 125,
+ AV_OPLACE_SNOW_4 = 126,
+ AV_OPLACE_MINE_SUPPLY_N_MIN = 127,
+ AV_OPLACE_MINE_SUPPLY_N_MAX = 136,
+ AV_OPLACE_MINE_SUPPLY_S_MIN = 137,
+ AV_OPLACE_MINE_SUPPLY_S_MAX = 148,
+
+ AV_OPLACE_MAX = 149
};
-const float BG_AV_ObjectPos[AV_OPLACE_MAX][4] =
+Position const BG_AV_ObjectPos[AV_OPLACE_MAX] =
{
{638.592f, -32.422f, 46.0608f, -1.62316f }, //firstaid station
{669.007f, -294.078f, 30.2909f, 2.77507f }, //stormpike
@@ -1228,59 +1229,59 @@ const float BG_AV_StaticCreaturePos[AV_STATICCPLACE_MAX][5] =
{-1370.9f, -219.793f, 98.4258f, 5.04381f, 47}, //drek thar
};
-const uint32 BG_AV_StaticCreatureInfo[51][4] =
+const uint32 BG_AV_StaticCreatureInfo[51] =
{
- { 2225, 1215, 55, 55 }, //Zora Guthrek
- { 3343, 1215, 55, 55 }, //Grelkor
- { 3625, 1215, 55, 55 }, //Rarck
- { 4255, 1217, 55, 55 }, //Brogus Thunderbrew
- { 4257, 1217, 55, 55 }, //Lana Thunderbrew
- { 5134, 1217, 55, 55 }, //Jonivera Farmountain
- { 5135, 1217, 55, 55 }, //Svalbrad Farmountain
- { 5139, 1217, 55, 55 }, //Kurdrum Barleybeard
- { 10364, 1215, 55, 55 }, //Yaelika Farclaw
- { 10367, 1215, 55, 55 }, //Shrye Ragefist
- { 10981, 38, 50, 51 }, //Frostwolf
- { 10986, 514, 52, 53 }, //Snowblind Harpy
- { 10990, 1274, 50, 51 }, //Alterac Ram
- { 11675, 514, 53, 53 }, //Snowblind Windcaller
- { 11678, 14, 52, 53 }, //Snowblind Ambusher
- { 11839, 39, 56, 56 }, //Wildpaw Brute
- { 11947, 1214, 61, 61 }, // Captain Galvangar /// @todo: Duplicate ? Check and confirm
- { 11948, 1216, 63, 63 }, //Vanndar Stormpike
- { 11949, 1216, 61, 61 }, //Captain Balinda Stonehearth
- { 11997, 1334, 60, 60 }, //Stormpike Herald
- { 12051, 1214, 57, 57 }, //Frostwolf Legionnaire
- { 12096, 1217, 55, 55 }, //Stormpike Quartermaster
- { 12097, 1215, 55, 55 }, //Frostwolf Quartermaster
- { 12127, 1216, 57, 57 }, //Stormpike Guardsman
- { 13176, 1215, 60, 60 }, //Smith Regzar
- { 13179, 1215, 59, 59 }, //Wing Commander Guse
- { 13216, 1217, 58, 58 }, //Gaelden Hammersmith
- { 13218, 1215, 58, 58 }, //Grunnda Wolfheart
- { 13236, 1214, 60, 60 }, //Primalist Thurloga
- { 13257, 1216, 60, 60 }, //Murgot Deepforge
- { 13284, 1214, 58, 58 }, //Frostwolf Shaman
- { 13438, 1217, 58, 58 }, //Wing Commander Slidore
- { 13442, 1216, 60, 60 }, //Arch Druid Renferal
- { 13443, 1216, 60, 60 }, //Druid of the Grove
- { 13447, 1216, 58, 58 }, //Corporal Noreg Stormpike
- { 13577, 1216, 60, 60 }, //Stormpike Ram Rider Commander
- { 13617, 1216, 60, 60 }, //Stormpike Stable Master
- { 13797, 32, 60, 61 }, //Mountaineer Boombellow
- { 13798, 1214, 60, 61 }, //Jotek
- { 13816, 1216, 61, 61 }, //Prospector Stonehewer
- { 14185, 877, 59, 59 }, //Najak Hexxen
- { 14186, 105, 60, 60 }, //Ravak Grimtotem
- { 14187, 1594, 60, 60 }, //Athramanis
- { 14188, 57, 59, 59 }, //Dirk Swindle
- { 14282, 1214, 53, 54 }, //Frostwolf Bloodhound
- { 14283, 1216, 53, 54 }, //Stormpike Owl
- { 14284, 1216, 61, 61 }, //Stormpike Battleguard
- { 11946, 1214, 63, 63 }, //Drek'Thar /// @todo: Correct the level (Level 80 for boss ?)
- { 11948, 1216, 63, 63 }, //Vanndar Stormpike
- { 11947, 1214, 61, 61 }, //Captain Galvangar
- { 11949, 1216, 61, 61 } //Captain Balinda Stonehearth
+ 2225, // Zora Guthrek
+ 3343, // Grelkor
+ 3625, // Rarck
+ 4255, // Brogus Thunderbrew
+ 4257, // Lana Thunderbrew
+ 5134, // Jonivera Farmountain
+ 5135, // Svalbrad Farmountain
+ 5139, // Kurdrum Barleybeard
+ 10364, // Yaelika Farclaw
+ 10367, // Shrye Ragefist
+ 10981, // Frostwolf
+ 10986, // Snowblind Harpy
+ 10990, // Alterac Ram
+ 11675, // Snowblind Windcaller
+ 11678, // Snowblind Ambusher
+ 11839, // Wildpaw Brute
+ 11947, // Captain Galvangar
+ 11948, // Vanndar Stormpike
+ 11949, // Captain Balinda Stonehearth
+ 11997, // Stormpike Herald
+ 12051, // Frostwolf Legionnaire
+ 12096, // Stormpike Quartermaster
+ 12097, // Frostwolf Quartermaster
+ 12127, // Stormpike Guardsman
+ 13176, // Smith Regzar
+ 13179, // Wing Commander Guse
+ 13216, // Gaelden Hammersmith
+ 13218, // Grunnda Wolfheart
+ 13236, // Primalist Thurloga
+ 13257, // Murgot Deepforge
+ 13284, // Frostwolf Shaman
+ 13438, // Wing Commander Slidore
+ 13442, // Arch Druid Renferal
+ 13443, // Druid of the Grove
+ 13447, // Corporal Noreg Stormpike
+ 13577, // Stormpike Ram Rider Commander
+ 13617, // Stormpike Stable Master
+ 13797, // Mountaineer Boombellow
+ 13798, // Jotek
+ 13816, // Prospector Stonehewer
+ 14185, // Najak Hexxen
+ 14186, // Ravak Grimtotem
+ 14187, // Athramanis
+ 14188, // Dirk Swindle
+ 14282, // Frostwolf Bloodhound
+ 14283, // Stormpike Owl
+ 14284, // Stormpike Battleguard
+ 11946, // Drek'Thar
+ 11948, // Vanndar Stormpike
+ 11947, // Captain Galvangar
+ 11949, // Captain Balinda Stonehearth
};
enum BG_AV_Graveyards
@@ -1525,18 +1526,53 @@ struct BG_AV_NodeInfo
inline BG_AV_Nodes &operator++(BG_AV_Nodes &i){ return i = BG_AV_Nodes(i + 1); }
-struct BattlegroundAVScore : public BattlegroundScore
+struct BattlegroundAVScore final : public BattlegroundScore
{
- BattlegroundAVScore() : GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0),
- TowersDefended(0), MinesCaptured(0), LeadersKilled(0), SecondaryObjectives(0) { }
- ~BattlegroundAVScore() { }
- uint32 GraveyardsAssaulted;
- uint32 GraveyardsDefended;
- uint32 TowersAssaulted;
- uint32 TowersDefended;
- uint32 MinesCaptured;
- uint32 LeadersKilled;
- uint32 SecondaryObjectives;
+ friend class BattlegroundAV;
+
+ protected:
+ BattlegroundAVScore(uint64 playerGuid) : BattlegroundScore(playerGuid), GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), MinesCaptured(0) { }
+
+ void UpdateScore(uint32 type, uint32 value) override
+ {
+ switch (type)
+ {
+ case SCORE_GRAVEYARDS_ASSAULTED:
+ GraveyardsAssaulted += value;
+ break;
+ case SCORE_GRAVEYARDS_DEFENDED:
+ GraveyardsDefended += value;
+ break;
+ case SCORE_TOWERS_ASSAULTED:
+ TowersAssaulted += value;
+ break;
+ case SCORE_TOWERS_DEFENDED:
+ TowersDefended += value;
+ break;
+ case SCORE_MINES_CAPTURED:
+ MinesCaptured += value;
+ break;
+ default:
+ BattlegroundScore::UpdateScore(type, value);
+ break;
+ }
+ }
+
+ void BuildObjectivesBlock(WorldPacket& data) final
+ {
+ data << uint32(5); // Objectives Count
+ data << uint32(GraveyardsAssaulted);
+ data << uint32(GraveyardsDefended);
+ data << uint32(TowersAssaulted);
+ data << uint32(TowersDefended);
+ data << uint32(MinesCaptured);
+ }
+
+ uint32 GraveyardsAssaulted;
+ uint32 GraveyardsDefended;
+ uint32 TowersAssaulted;
+ uint32 TowersDefended;
+ uint32 MinesCaptured;
};
class BattlegroundAV : public Battleground
@@ -1557,7 +1593,7 @@ class BattlegroundAV : public Battleground
/*general stuff*/
void UpdateScore(uint16 team, int16 points);
- void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
+ bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
/*handlestuff*/ //these are functions which get called from extern
void EventPlayerClickedOnFlag(Player* source, GameObject* target_obj);
@@ -1607,7 +1643,6 @@ class BattlegroundAV : public Battleground
/*general */
Creature* AddAVCreature(uint16 cinfoid, uint16 type);
- uint16 GetBonusHonor(uint8 kills); /// @todo: Remove this when the core handles this properly
/*variables */
int32 m_Team_Scores[2];
@@ -1622,7 +1657,6 @@ class BattlegroundAV : public Battleground
uint32 m_CaptainBuffTimer[2];
bool m_CaptainAlive[2];
- uint8 m_MaxLevel; /// @todo: Remove this once battleground->getmaxlevel() returns something usefull/is reworked (?)
bool m_IsInformedNearVictory[2];
};
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp
index c89fc57b8aa..548e0bf463b 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp
@@ -16,6 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "ArenaScore.h"
#include "BattlegroundBE.h"
#include "Language.h"
#include "Object.h"
@@ -64,7 +65,7 @@ void BattlegroundBE::StartingEventOpenDoors()
void BattlegroundBE::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- PlayerScores[player->GetGUID()] = new BattlegroundScore;
+ PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam());
UpdateArenaWorldState();
}
@@ -139,13 +140,3 @@ bool BattlegroundBE::SetupBattleground()
return true;
}
-
-void BattlegroundBE::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor)
-{
- BattlegroundScoreMap::iterator itr = PlayerScores.find(Source->GetGUID());
- if (itr == PlayerScores.end()) // player not found...
- return;
-
- //there is nothing special in this score
- Battleground::UpdatePlayerScore(Source, type, value, doAddHonor);
-}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBE.h b/src/server/game/Battlegrounds/Zones/BattlegroundBE.h
index be801dfff2b..6fd4dc37fc8 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundBE.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundBE.h
@@ -59,8 +59,5 @@ class BattlegroundBE : public Battleground
void Reset();
void FillInitialWorldStates(WorldPacket &d);
void HandleKillPlayer(Player* player, Player* killer);
-
- /* Scorekeeping */
- void UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor = true);
};
#endif
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp
index 9e9e82b32b8..1d6970f8317 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp
@@ -16,6 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "ArenaScore.h"
#include "BattlegroundDS.h"
#include "Creature.h"
#include "GameObject.h"
@@ -152,7 +153,7 @@ void BattlegroundDS::StartingEventOpenDoors()
void BattlegroundDS::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- PlayerScores[player->GetGUID()] = new BattlegroundScore;
+ PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam());
UpdateArenaWorldState();
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
index 213a91bea88..ca96140f5da 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
@@ -363,12 +363,9 @@ void BattlegroundEY::UpdatePointsIcons(uint32 Team, uint32 Point)
void BattlegroundEY::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- //create score and add it to map
- BattlegroundEYScore* sc = new BattlegroundEYScore;
+ PlayerScores[player->GetGUIDLow()] = new BattlegroundEYScore(player->GetGUID());
m_PlayersNearPoint[EY_POINTS_MAX].push_back(player->GetGUID());
-
- PlayerScores[player->GetGUID()] = sc;
}
void BattlegroundEY::RemovePlayer(Player* player, uint64 guid, uint32 /*team*/)
@@ -832,22 +829,20 @@ void BattlegroundEY::EventPlayerCapturedFlag(Player* player, uint32 BgObjectType
UpdatePlayerScore(player, SCORE_FLAG_CAPTURES, 1);
}
-void BattlegroundEY::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
+bool BattlegroundEY::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{
- BattlegroundScoreMap::iterator itr = PlayerScores.find(player->GetGUID());
- if (itr == PlayerScores.end()) // player not found
- return;
+ if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor))
+ return false;
switch (type)
{
- case SCORE_FLAG_CAPTURES: // flags captured
- ((BattlegroundEYScore*)itr->second)->FlagCaptures += value;
+ case SCORE_FLAG_CAPTURES:
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, EY_OBJECTIVE_CAPTURE_FLAG);
break;
default:
- Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
break;
}
+ return true;
}
void BattlegroundEY::FillInitialWorldStates(WorldPacket& data)
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h
index 9e5088d7ba5..056deb3498b 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h
@@ -20,6 +20,7 @@
#define __BATTLEGROUNDEY_H
#include "Battleground.h"
+#include "BattlegroundScore.h"
#include "Language.h"
#include "Object.h"
@@ -322,11 +323,33 @@ const BattlegroundEYCapturingPointStruct m_CapturingPointTypes[EY_POINTS_MAX] =
BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_H_M_TOWER, EY_GRAVEYARD_MAGE_TOWER)
};
-struct BattlegroundEYScore : public BattlegroundScore
+struct BattlegroundEYScore final : public BattlegroundScore
{
- BattlegroundEYScore() : FlagCaptures(0) { }
- ~BattlegroundEYScore() { }
- uint32 FlagCaptures;
+ friend class BattlegroundEY;
+
+ protected:
+ BattlegroundEYScore(uint64 playerGuid) : BattlegroundScore(playerGuid), FlagCaptures(0) { }
+
+ void UpdateScore(uint32 type, uint32 value) override
+ {
+ switch (type)
+ {
+ case SCORE_FLAG_CAPTURES: // Flags captured
+ FlagCaptures += value;
+ break;
+ default:
+ BattlegroundScore::UpdateScore(type, value);
+ break;
+ }
+ }
+
+ void BuildObjectivesBlock(WorldPacket& data) final
+ {
+ data << uint32(1); // Objectives Count
+ data << uint32(FlagCaptures);
+ }
+
+ uint32 FlagCaptures;
};
class BattlegroundEY : public Battleground
@@ -357,7 +380,7 @@ class BattlegroundEY : public Battleground
void Reset();
void UpdateTeamScore(uint32 Team);
void EndBattleground(uint32 winner);
- void UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor = true);
+ bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
void FillInitialWorldStates(WorldPacket& data);
void SetDroppedFlagGUID(uint64 guid, int32 /*TeamID*/ = -1) { m_DroppedFlagGUID = guid;}
uint64 GetDroppedFlagGUID() const { return m_DroppedFlagGUID;}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
index 9e9cc6c63ee..da0b00af40f 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
@@ -80,12 +80,11 @@ void BattlegroundIC::DoAction(uint32 action, uint64 var)
if (!player)
return;
- player->SetTransport(player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde);
+ (player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->AddPassenger(player);
player->m_movementInfo.transport.pos.m_positionX = TransportMovementInfo.GetPositionX();
player->m_movementInfo.transport.pos.m_positionY = TransportMovementInfo.GetPositionY();
player->m_movementInfo.transport.pos.m_positionZ = TransportMovementInfo.GetPositionZ();
- player->m_movementInfo.transport.guid = (player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->GetGUID();
if (player->TeleportTo(GetMapId(), TeleportToTransportPosition.GetPositionX(),
TeleportToTransportPosition.GetPositionY(),
@@ -274,7 +273,7 @@ void BattlegroundIC::StartingEventOpenDoors()
void BattlegroundIC::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- PlayerScores[player->GetGUID()] = new BattlegroundICScore;
+ PlayerScores[player->GetGUIDLow()] = new BattlegroundICScore(player->GetGUID());
if (nodePoint[NODE_TYPE_QUARRY].nodeState == (player->GetTeamId() == TEAM_ALLIANCE ? NODE_STATE_CONTROLLED_A : NODE_STATE_CONTROLLED_H))
player->CastSpell(player, SPELL_QUARRY, true);
@@ -315,27 +314,6 @@ void BattlegroundIC::HandleAreaTrigger(Player* player, uint32 trigger)
}
}
-void BattlegroundIC::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
-{
- std::map<uint64, BattlegroundScore*>::iterator itr = PlayerScores.find(player->GetGUID());
-
- if (itr == PlayerScores.end()) // player not found...
- return;
-
- switch (type)
- {
- case SCORE_BASES_ASSAULTED:
- ((BattlegroundICScore*)itr->second)->BasesAssaulted += value;
- break;
- case SCORE_BASES_DEFENDED:
- ((BattlegroundICScore*)itr->second)->BasesDefended += value;
- break;
- default:
- Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
- break;
- }
-}
-
void BattlegroundIC::FillInitialWorldStates(WorldPacket& data)
{
data << uint32(BG_IC_ALLIANCE_RENFORT_SET) << uint32(1);
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h
index 091a75e7449..0b317cabef3 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h
@@ -20,6 +20,7 @@
#define __BATTLEGROUNDIC_H
#include "Battleground.h"
+#include "BattlegroundScore.h"
#include "Language.h"
#include "Object.h"
@@ -847,12 +848,38 @@ enum HonorRewards
WINNER_HONOR_AMOUNT = 500
};
-struct BattlegroundICScore : public BattlegroundScore
+struct BattlegroundICScore final : public BattlegroundScore
{
- BattlegroundICScore() : BasesAssaulted(0), BasesDefended(0) { }
- ~BattlegroundICScore() { }
- uint32 BasesAssaulted;
- uint32 BasesDefended;
+ friend class BattlegroundIC;
+
+ protected:
+ BattlegroundICScore(uint64 playerGuid) : BattlegroundScore(playerGuid), BasesAssaulted(0), BasesDefended(0) { }
+
+ void UpdateScore(uint32 type, uint32 value) override
+ {
+ switch (type)
+ {
+ case SCORE_BASES_ASSAULTED:
+ BasesAssaulted += value;
+ break;
+ case SCORE_BASES_DEFENDED:
+ BasesDefended += value;
+ break;
+ default:
+ BattlegroundScore::UpdateScore(type, value);
+ break;
+ }
+ }
+
+ void BuildObjectivesBlock(WorldPacket& data) final
+ {
+ data << uint32(2); // Objectives Count
+ data << uint32(BasesAssaulted);
+ data << uint32(BasesDefended);
+ }
+
+ uint32 BasesAssaulted;
+ uint32 BasesDefended;
};
class BattlegroundIC : public Battleground
@@ -881,8 +908,6 @@ class BattlegroundIC : public Battleground
WorldSafeLocsEntry const* GetClosestGraveYard(Player* player);
/* Scorekeeping */
- void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
-
void FillInitialWorldStates(WorldPacket& data);
void DoAction(uint32 action, uint64 var);
@@ -894,6 +919,7 @@ class BattlegroundIC : public Battleground
bool IsAllNodesControlledByTeam(uint32 team) const;
bool IsSpellAllowed(uint32 spellId, Player const* player) const;
+
private:
uint32 closeFortressDoorsTimer;
bool doorsClosed;
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp
index 70a940ec853..82fcb2f6f91 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp
@@ -16,6 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "ArenaScore.h"
#include "BattlegroundNA.h"
#include "Language.h"
#include "Object.h"
@@ -61,7 +62,7 @@ void BattlegroundNA::StartingEventOpenDoors()
void BattlegroundNA::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- PlayerScores[player->GetGUID()] = new BattlegroundScore;
+ PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam());
UpdateArenaWorldState();
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp
index 5f77c57c064..712d9a6e296 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp
@@ -16,6 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "ArenaScore.h"
#include "BattlegroundRL.h"
#include "Language.h"
#include "Object.h"
@@ -61,7 +62,7 @@ void BattlegroundRL::StartingEventOpenDoors()
void BattlegroundRL::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- PlayerScores[player->GetGUID()] = new BattlegroundScore;
+ PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam());
UpdateArenaWorldState();
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp
index dd61b8b9e6f..1059124d041 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp
@@ -16,6 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "ArenaScore.h"
#include "Battleground.h"
#include "BattlegroundRV.h"
#include "ObjectAccessor.h"
@@ -99,7 +100,7 @@ void BattlegroundRV::StartingEventOpenDoors()
void BattlegroundRV::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- PlayerScores[player->GetGUID()] = new BattlegroundScore;
+ PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam());
UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE));
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
index 0966ddd19bd..7e90c0b3db0 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
@@ -454,9 +454,7 @@ void BattlegroundSA::FillInitialWorldStates(WorldPacket& data)
void BattlegroundSA::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- //create score and add it to map, default values are set in constructor
- BattlegroundSAScore* sc = new BattlegroundSAScore;
- PlayerScores[player->GetGUID()] = sc;
+ PlayerScores[player->GetGUIDLow()] = new BattlegroundSAScore(player->GetGUID());
SendTransportInit(player);
@@ -493,20 +491,6 @@ void BattlegroundSA::HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/)
return;
}
-void BattlegroundSA::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor)
-{
- BattlegroundScoreMap::iterator itr = PlayerScores.find(Source->GetGUID());
- if (itr == PlayerScores.end()) // player not found...
- return;
-
- if (type == SCORE_DESTROYED_DEMOLISHER)
- ((BattlegroundSAScore*)itr->second)->demolishers_destroyed += value;
- else if (type == SCORE_DESTROYED_WALL)
- ((BattlegroundSAScore*)itr->second)->gates_destroyed += value;
- else
- Battleground::UpdatePlayerScore(Source, type, value, doAddHonor);
-}
-
void BattlegroundSA::TeleportPlayers()
{
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h
index 880da0735f4..a3947334417 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h
@@ -20,16 +20,9 @@
#define __BATTLEGROUNDSA_H
#include "Battleground.h"
+#include "BattlegroundScore.h"
#include "Object.h"
-struct BattlegroundSAScore : public BattlegroundScore
-{
- BattlegroundSAScore() : demolishers_destroyed(0), gates_destroyed(0) { }
- ~BattlegroundSAScore() { }
- uint8 demolishers_destroyed;
- uint8 gates_destroyed;
-};
-
#define BG_SA_FLAG_AMOUNT 3
#define BG_SA_DEMOLISHER_AMOUNT 4
@@ -249,7 +242,7 @@ uint32 const BG_SA_NpcEntries[BG_SA_MAXNPC] =
NPC_KANRETHAD
};
-Position const BG_SA_NpcSpawnlocs[BG_SA_MAXNPC + BG_SA_DEMOLISHER_AMOUNT] =
+Position const BG_SA_NpcSpawnlocs[BG_SA_MAXNPC] =
{
// Cannons
{ 1436.429f, 110.05f, 41.407f, 5.4f },
@@ -515,6 +508,40 @@ struct BG_SA_RoundScore
uint32 time;
};
+struct BattlegroundSAScore final : public BattlegroundScore
+{
+ friend class BattlegroundSA;
+
+ protected:
+ BattlegroundSAScore(uint64 playerGuid) : BattlegroundScore(playerGuid), DemolishersDestroyed(0), GatesDestroyed(0) { }
+
+ void UpdateScore(uint32 type, uint32 value) override
+ {
+ switch (type)
+ {
+ case SCORE_DESTROYED_DEMOLISHER:
+ DemolishersDestroyed += value;
+ break;
+ case SCORE_DESTROYED_WALL:
+ GatesDestroyed += value;
+ break;
+ default:
+ BattlegroundScore::UpdateScore(type, value);
+ break;
+ }
+ }
+
+ void BuildObjectivesBlock(WorldPacket& data) final
+ {
+ data << uint32(2); // Objectives Count
+ data << uint32(DemolishersDestroyed);
+ data << uint32(GatesDestroyed);
+ }
+
+ uint32 DemolishersDestroyed;
+ uint32 GatesDestroyed;
+};
+
/// Class for manage Strand of Ancient battleground
class BattlegroundSA : public Battleground
{
@@ -568,8 +595,6 @@ class BattlegroundSA : public Battleground
void HandleAreaTrigger(Player* Source, uint32 Trigger);
/* Scorekeeping */
- /// Update score board
- void UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor = true);
// Achievement: Not Even a Scratch
bool CheckAchievementCriteriaMeet(uint32 criteriaId, Player const* source, Unit const* target = NULL, uint32 miscValue = 0) override;
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
index fcd55e2e16a..1faa3361975 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
@@ -229,10 +229,7 @@ void BattlegroundWS::StartingEventOpenDoors()
void BattlegroundWS::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
- //create score and add it to map, default values are set in constructor
- BattlegroundWGScore* sc = new BattlegroundWGScore;
-
- PlayerScores[player->GetGUID()] = sc;
+ PlayerScores[player->GetGUIDLow()] = new BattlegroundWGScore(player->GetGUID());
}
void BattlegroundWS::RespawnFlag(uint32 Team, bool captured)
@@ -790,26 +787,23 @@ void BattlegroundWS::HandleKillPlayer(Player* player, Player* killer)
Battleground::HandleKillPlayer(player, killer);
}
-void BattlegroundWS::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
+bool BattlegroundWS::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{
- BattlegroundScoreMap::iterator itr = PlayerScores.find(player->GetGUID());
- if (itr == PlayerScores.end()) // player not found
- return;
+ if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor))
+ return false;
switch (type)
{
case SCORE_FLAG_CAPTURES: // flags captured
- ((BattlegroundWGScore*)itr->second)->FlagCaptures += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_CAPTURE_FLAG);
break;
case SCORE_FLAG_RETURNS: // flags returned
- ((BattlegroundWGScore*)itr->second)->FlagReturns += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_RETURN_FLAG);
break;
default:
- Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
break;
}
+ return true;
}
WorldSafeLocsEntry const* BattlegroundWS::GetClosestGraveYard(Player* player)
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h
index c6c25ec52de..3d449580fb9 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h
@@ -20,6 +20,7 @@
#define __BATTLEGROUNDWS_H
#include "Battleground.h"
+#include "BattlegroundScore.h"
enum BG_WS_TimerOrScore
{
@@ -146,12 +147,38 @@ enum BG_WS_Objectives
#define WS_EVENT_START_BATTLE 8563
-struct BattlegroundWGScore : public BattlegroundScore
+struct BattlegroundWGScore final : public BattlegroundScore
{
- BattlegroundWGScore() : FlagCaptures(0), FlagReturns(0) { }
- ~BattlegroundWGScore() { }
- uint32 FlagCaptures;
- uint32 FlagReturns;
+ friend class BattlegroundWS;
+
+ protected:
+ BattlegroundWGScore(uint64 playerGuid) : BattlegroundScore(playerGuid), FlagCaptures(0), FlagReturns(0) { }
+
+ void UpdateScore(uint32 type, uint32 value) override
+ {
+ switch (type)
+ {
+ case SCORE_FLAG_CAPTURES: // Flags captured
+ FlagCaptures += value;
+ break;
+ case SCORE_FLAG_RETURNS: // Flags returned
+ FlagReturns += value;
+ break;
+ default:
+ BattlegroundScore::UpdateScore(type, value);
+ break;
+ }
+ }
+
+ void BuildObjectivesBlock(WorldPacket& data) final
+ {
+ data << uint32(2); // Objectives Count
+ data << uint32(FlagCaptures);
+ data << uint32(FlagReturns);
+ }
+
+ uint32 FlagCaptures;
+ uint32 FlagReturns;
};
class BattlegroundWS : public Battleground
@@ -197,7 +224,7 @@ class BattlegroundWS : public Battleground
void UpdateFlagState(uint32 team, uint32 value);
void SetLastFlagCapture(uint32 team) { _lastFlagCaptureTeam = team; }
void UpdateTeamScore(uint32 team);
- void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
+ bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
void SetDroppedFlagGUID(uint64 guid, int32 team = -1)
{
if (team == TEAM_ALLIANCE || team == TEAM_HORDE)
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt
index bf46c1fd7c6..26fd0814dcb 100644
--- a/src/server/game/CMakeLists.txt
+++ b/src/server/game/CMakeLists.txt
@@ -103,7 +103,9 @@ set(game_STAT_SRCS
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/zlib
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index ec048e167ac..10b7c25bb1f 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -349,21 +349,20 @@ enum ItemLimitCategoryMode
ITEM_LIMIT_CATEGORY_MODE_EQUIP = 1 // limit applied to amount equipped items (including used gems)
};
-enum SpellCategoryFlags
+enum SkillRaceClassInfoFlags
{
- SPELL_CATEGORY_FLAG_COOLDOWN_SCALES_WITH_WEAPON_SPEED = 0x01, // unused
- SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT = 0x04
+ SKILL_FLAG_NO_SKILLUP_MESSAGE = 0x2,
+ SKILL_FLAG_ALWAYS_MAX_VALUE = 0x10,
+ SKILL_FLAG_UNLEARNABLE = 0x20, // Skill can be unlearned
+ SKILL_FLAG_INCLUDE_IN_SORT = 0x80, // Spells belonging to a skill with this flag will additionally compare skill ids when sorting spellbook in client
+ SKILL_FLAG_NOT_TRAINABLE = 0x100,
+ SKILL_FLAG_MONO_VALUE = 0x400 // Skill always has value 1
};
-enum TotemCategoryType
+enum SpellCategoryFlags
{
- TOTEM_CATEGORY_TYPE_KNIFE = 1,
- TOTEM_CATEGORY_TYPE_TOTEM = 2,
- TOTEM_CATEGORY_TYPE_ROD = 3,
- TOTEM_CATEGORY_TYPE_PICK = 21,
- TOTEM_CATEGORY_TYPE_STONE = 22,
- TOTEM_CATEGORY_TYPE_HAMMER = 23,
- TOTEM_CATEGORY_TYPE_SPANNER = 24
+ SPELL_CATEGORY_FLAG_COOLDOWN_SCALES_WITH_WEAPON_SPEED = 0x01, // unused
+ SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT = 0x04
};
// SummonProperties.dbc, col 1
@@ -398,6 +397,17 @@ enum SummonPropFlags
SUMMON_PROP_FLAG_UNK16 = 0x00008000 // Light/Dark Bullet, Soul/Fiery Consumption, Twisted Visage, Twilight Whelp. Phase related?
};
+enum TotemCategoryType
+{
+ TOTEM_CATEGORY_TYPE_KNIFE = 1,
+ TOTEM_CATEGORY_TYPE_TOTEM = 2,
+ TOTEM_CATEGORY_TYPE_ROD = 3,
+ TOTEM_CATEGORY_TYPE_PICK = 21,
+ TOTEM_CATEGORY_TYPE_STONE = 22,
+ TOTEM_CATEGORY_TYPE_HAMMER = 23,
+ TOTEM_CATEGORY_TYPE_SPANNER = 24
+};
+
enum VehicleSeatFlags
{
VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_ENTER = 0x00000001,
@@ -442,6 +452,7 @@ enum VehicleSeatFlagsB
VEHICLE_SEAT_FLAG_B_EJECTABLE = 0x00000020, // ejectable
VEHICLE_SEAT_FLAG_B_USABLE_FORCED_2 = 0x00000040,
VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3 = 0x00000100,
+ VEHICLE_SEAT_FLAG_B_KEEP_PET = 0x00020000,
VEHICLE_SEAT_FLAG_B_USABLE_FORCED_4 = 0x02000000,
VEHICLE_SEAT_FLAG_B_CAN_SWITCH = 0x04000000,
VEHICLE_SEAT_FLAG_B_VEHICLE_PLAYERFRAME_UI = 0x80000000 // Lua_UnitHasVehiclePlayerFrameUI - actually checked for flagsb &~ 0x80000000
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 44f03b6978d..92d00b20645 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -151,6 +151,9 @@ DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore(ScalingStatValuesfmt
DBCStorage <SkillLineEntry> sSkillLineStore(SkillLinefmt);
DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore(SkillLineAbilityfmt);
+DBCStorage <SkillRaceClassInfoEntry> sSkillRaceClassInfoStore(SkillRaceClassInfofmt);
+SkillRaceClassInfoMap SkillRaceClassInfoBySkill;
+DBCStorage <SkillTiersEntry> sSkillTiersStore(SkillTiersfmt);
DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
@@ -409,6 +412,13 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatValuesStore, dbcPath, "ScalingStatValues.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineStore, dbcPath, "SkillLine.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineAbilityStore, dbcPath, "SkillLineAbility.dbc");
+ LoadDBC(availableDbcLocales, bad_dbc_files, sSkillRaceClassInfoStore, dbcPath, "SkillRaceClassInfo.dbc");
+ for (uint32 i = 0; i < sSkillRaceClassInfoStore.GetNumRows(); ++i)
+ if (SkillRaceClassInfoEntry const* entry = sSkillRaceClassInfoStore.LookupEntry(i))
+ if (sSkillLineStore.LookupEntry(entry->SkillId))
+ SkillRaceClassInfoBySkill.emplace(entry->SkillId, entry);
+
+ LoadDBC(availableDbcLocales, bad_dbc_files, sSkillTiersStore, dbcPath, "SkillTiers.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sSoundEntriesStore, dbcPath, "SoundEntries.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc", &CustomSpellEntryfmt, &CustomSpellEntryIndex);
for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
@@ -965,3 +975,19 @@ uint32 GetDefaultMapLight(uint32 mapId)
return 0;
}
+
+SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_)
+{
+ SkillRaceClassInfoBounds bounds = SkillRaceClassInfoBySkill.equal_range(skill);
+ for (SkillRaceClassInfoMap::iterator itr = bounds.first; itr != bounds.second; ++itr)
+ {
+ if (itr->second->RaceMask && !(itr->second->RaceMask & (1 << (race - 1))))
+ continue;
+ if (itr->second->ClassMask && !(itr->second->ClassMask & (1 << (class_ - 1))))
+ continue;
+
+ return itr->second;
+ }
+
+ return NULL;
+}
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index fe775dfda19..8b89a86fafe 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -74,6 +74,10 @@ LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty);
uint32 GetDefaultMapLight(uint32 mapId);
+typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRaceClassInfoMap;
+typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds;
+SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
+
extern DBCStorage <AchievementEntry> sAchievementStore;
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
@@ -150,6 +154,7 @@ extern DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore;
extern DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore;
extern DBCStorage <SkillLineEntry> sSkillLineStore;
extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore;
+extern DBCStorage <SkillTiersEntry> sSkillTiersStore;
extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore;
extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore;
extern DBCStorage <SpellCategoryEntry> sSpellCategoryStore;
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 5d6c8c7aa89..2da166fb049 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1584,6 +1584,27 @@ struct SkillLineAbilityEntry
//uint32 characterPoints[2]; // 12-13 m_characterPoints[2]
};
+struct SkillRaceClassInfoEntry
+{
+ //uint32 Id; // 0
+ uint32 SkillId; // 1
+ uint32 RaceMask; // 2
+ uint32 ClassMask; // 3
+ uint32 Flags; // 4
+ //uint32 MinLevel; // 5
+ uint32 SkillTier; // 6
+ //uint32 SkillCostType; // 7
+};
+
+#define MAX_SKILL_STEP 16
+
+struct SkillTiersEntry
+{
+ uint32 Id; // 0
+ //uint32 StepCost[MAX_SKILL_STEP]; // 1-16
+ uint32 MaxSkill[MAX_SKILL_STEP]; // 17-32
+};
+
struct SoundEntriesEntry
{
uint32 Id; // 0 m_ID
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index 222353467f4..a90cc48c5af 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -98,6 +98,8 @@ char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiii";
char const ScalingStatValuesfmt[] = "iniiiiiiiiiiiiiiiiiiiiii";
char const SkillLinefmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxi";
char const SkillLineAbilityfmt[] = "niiiixxiiiiixx";
+char const SkillRaceClassInfofmt[] = "diiiixix";
+char const SkillTiersfmt[] = "nxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiii";
char const SoundEntriesfmt[] = "nxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
char const SpellCastTimefmt[] = "nixx";
char const SpellCategoryfmt[] = "ni";
diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp
index aadf1529ffd..181e04e04fc 100644
--- a/src/server/game/DungeonFinding/LFGScripts.cpp
+++ b/src/server/game/DungeonFinding/LFGScripts.cpp
@@ -46,7 +46,7 @@ void LFGPlayerScript::OnLogout(Player* player)
}
}
-void LFGPlayerScript::OnLogin(Player* player)
+void LFGPlayerScript::OnLogin(Player* player, bool /*loginFirst*/)
{
if (!sLFGMgr->isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER))
return;
diff --git a/src/server/game/DungeonFinding/LFGScripts.h b/src/server/game/DungeonFinding/LFGScripts.h
index 87881ed7524..1ed37bd9d05 100644
--- a/src/server/game/DungeonFinding/LFGScripts.h
+++ b/src/server/game/DungeonFinding/LFGScripts.h
@@ -36,7 +36,7 @@ class LFGPlayerScript : public PlayerScript
// Player Hooks
void OnLogout(Player* player);
- void OnLogin(Player* player);
+ void OnLogin(Player* player, bool loginFirst);
void OnMapChanged(Player* player);
};
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 90527912efd..19d32b41c93 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -142,8 +142,8 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
}
Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(),
-lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0),
-m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0),
+m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0),
+m_lootRecipient(0), m_lootRecipientGroup(0), _skinner(0), _pickpocketLootRestore(0), m_corpseRemoveTime(0), m_respawnTime(0),
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE),
m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
@@ -547,6 +547,15 @@ void Creature::Update(uint32 diff)
if (!IsAlive())
break;
+ time_t now = time(NULL);
+
+ // Check if we should refill the pickpocketing loot
+ if (loot.loot_type == LOOT_PICKPOCKETING && _pickpocketLootRestore && _pickpocketLootRestore <= now)
+ {
+ loot.clear();
+ _pickpocketLootRestore = 0;
+ }
+
if (m_regenTimer > 0)
{
if (diff >= m_regenTimer)
@@ -567,13 +576,13 @@ void Creature::Update(uint32 diff)
if (!IsInEvadeMode() && (!bInCombat || IsPolymorphed())) // regenerate health if not in combat or if polymorphed
RegenerateHealth();
- if (getPowerType() == POWER_ENERGY)
+ if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER))
{
- if (!IsVehicle() || GetVehicleKit()->GetVehicleInfo()->m_powerDisplayId != POWER_PYRITE)
+ if (getPowerType() == POWER_ENERGY)
Regenerate(POWER_ENERGY);
+ else
+ RegenerateMana();
}
- else
- RegenerateMana();
/*if (!bIsPolymorphed) // only increase the timer if not polymorphed
m_regenTimer += CREATURE_REGEN_INTERVAL - diff;
@@ -1173,14 +1182,22 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 entry, CreatureData const*
SetOriginalEntry(entry);
- if (!vehId)
- vehId = cinfo->VehicleId;
-
- Object::_Create(guidlow, entry, vehId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT);
+ Object::_Create(guidlow, entry, (vehId || cinfo->VehicleId) ? HIGHGUID_VEHICLE : HIGHGUID_UNIT);
if (!UpdateEntry(entry, data))
return false;
+ if (!vehId)
+ {
+ if (GetCreatureTemplate()->VehicleId)
+ {
+ vehId = GetCreatureTemplate()->VehicleId;
+ entry = GetCreatureTemplate()->Entry;
+ }
+ else
+ vehId = cinfo->VehicleId;
+ }
+
if (vehId)
CreateVehicleKit(vehId, entry);
@@ -1455,11 +1472,6 @@ void Creature::setDeathState(DeathState s)
setActive(false);
- if (!IsPet() && GetCreatureTemplate()->SkinLootId)
- if (LootTemplates_Skinning.HaveLootFor(GetCreatureTemplate()->SkinLootId))
- if (hasLootRecipient())
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
-
if (HasSearchedAssistance())
{
SetNoSearchAssistance(false);
@@ -1519,9 +1531,8 @@ void Creature::Respawn(bool force)
TC_LOG_DEBUG("entities.unit", "Respawning creature %s (GuidLow: %u, Full GUID: " UI64FMTD " Entry: %u)",
GetName().c_str(), GetGUIDLow(), GetGUID(), GetEntry());
m_respawnTime = 0;
- lootForPickPocketed = false;
- lootForBody = false;
-
+ _pickpocketLootRestore = 0;
+ loot.clear();
if (m_originalEntry != GetEntry())
UpdateEntry(m_originalEntry);
@@ -2260,26 +2271,23 @@ void Creature::GetRespawnPosition(float &x, float &y, float &z, float* ori, floa
void Creature::AllLootRemovedFromCorpse()
{
- if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE))
- {
- time_t now = time(NULL);
- if (m_corpseRemoveTime <= now)
- return;
+ if (loot.loot_type != LOOT_SKINNING && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient())
+ if (LootTemplates_Skinning.HaveLootFor(GetCreatureTemplate()->SkinLootId))
+ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
- float decayRate;
- CreatureTemplate const* cinfo = GetCreatureTemplate();
+ time_t now = time(NULL);
+ if (m_corpseRemoveTime <= now)
+ return;
- decayRate = sWorld->getRate(RATE_CORPSE_DECAY_LOOTED);
- uint32 diff = uint32((m_corpseRemoveTime - now) * decayRate);
+ float decayRate = sWorld->getRate(RATE_CORPSE_DECAY_LOOTED);
- m_respawnTime -= diff;
+ // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
+ if (loot.loot_type == LOOT_SKINNING)
+ m_corpseRemoveTime = time(NULL);
+ else
+ m_corpseRemoveTime = now + m_corpseDelay * decayRate;
- // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
- if (cinfo && cinfo->SkinLootId)
- m_corpseRemoveTime = time(NULL);
- else
- m_corpseRemoveTime -= diff;
- }
+ m_respawnTime = m_corpseRemoveTime + m_respawnTime;
}
uint8 Creature::getLevelForTarget(WorldObject const* target) const
@@ -2704,3 +2712,8 @@ void Creature::ReleaseFocus(Spell const* focusSpell)
ClearUnitState(UNIT_STATE_ROTATING);
}
+void Creature::StartPickPocketRefillTimer()
+{
+ _pickpocketLootRestore = time(NULL) + sWorld->getIntConfig(CONFIG_CREATURE_PICKPOCKET_REFILL);
+}
+
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 9cc08e3b71d..ca536e44e43 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -551,8 +551,10 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
virtual void DeleteFromDB(); // overriden in Pet
Loot loot;
- bool lootForPickPocketed;
- bool lootForBody;
+ void StartPickPocketRefillTimer();
+ void ResetPickPocketRefillTimer() { _pickpocketLootRestore = 0; }
+ void SetSkinner(uint64 guid) { _skinner = guid; }
+ uint64 GetSkinner() const { return _skinner; } // Returns the player who skinned this creature
Player* GetLootRecipient() const;
Group* GetLootRecipientGroup() const;
bool hasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; }
@@ -688,8 +690,10 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
uint64 m_lootRecipient;
uint32 m_lootRecipientGroup;
+ uint64 _skinner;
/// Timers
+ time_t _pickpocketLootRestore;
time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance
time_t m_respawnTime; // (secs) time of next respawn
uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning
diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
index 7cc94d992a1..e008146bb85 100644
--- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp
+++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
@@ -48,18 +48,6 @@ DynamicObject::~DynamicObject()
delete _removedAura;
}
-void DynamicObject::CleanupsBeforeDelete(bool finalCleanup /* = true */)
-{
- WorldObject::CleanupsBeforeDelete(finalCleanup);
-
- if (Transport* transport = GetTransport())
- {
- transport->RemovePassenger(this);
- SetTransport(NULL);
- m_movementInfo.transport.Reset();
- }
-}
-
void DynamicObject::AddToWorld()
{
///- Register the dynamicObject for guid lookup and for caster
@@ -124,14 +112,11 @@ bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spe
Transport* transport = caster->GetTransport();
if (transport)
{
- m_movementInfo.transport.guid = GetGUID();
-
float x, y, z, o;
pos.GetPosition(x, y, z, o);
transport->CalculatePassengerOffset(x, y, z, &o);
m_movementInfo.transport.pos.Relocate(x, y, z, o);
- SetTransport(transport);
// This object must be added to transport before adding to map for the client to properly display it
transport->AddPassenger(this);
}
diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h
index f52c86afdee..c9fd1d29f8b 100644
--- a/src/server/game/Entities/DynamicObject/DynamicObject.h
+++ b/src/server/game/Entities/DynamicObject/DynamicObject.h
@@ -41,8 +41,6 @@ class DynamicObject : public WorldObject, public GridObject<DynamicObject>, publ
void AddToWorld();
void RemoveFromWorld();
- void CleanupsBeforeDelete(bool finalCleanup = true) override;
-
bool CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type);
void Update(uint32 p_time);
void Remove();
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 370696474ae..ae08a4251a5 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -98,20 +98,12 @@ std::string GameObject::GetAIName() const
return "";
}
-void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
+void GameObject::CleanupsBeforeDelete(bool finalCleanup)
{
- if (IsInWorld())
- RemoveFromWorld();
+ WorldObject::CleanupsBeforeDelete(finalCleanup);
if (m_uint32Values) // field array can be not exist if GameOBject not loaded
RemoveFromOwner();
-
- if (GetTransport() && !ToTransport())
- {
- GetTransport()->RemovePassenger(this);
- SetTransport(NULL);
- m_movementInfo.transport.Reset();
- }
}
void GameObject::RemoveFromOwner()
@@ -696,12 +688,39 @@ void GameObject::getFishLoot(Loot* fishloot, Player* loot_owner)
fishloot->clear();
uint32 zone, subzone;
+ uint32 defaultzone = 1;
GetZoneAndAreaId(zone, subzone);
// if subzone loot exist use it
- if (!fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true))
- // else use zone loot (must exist in like case)
- fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true);
+ fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true);
+ if (fishloot->empty()) //use this becase if zone or subzone has set LOOT_MODE_JUNK_FISH,Even if no normal drop, fishloot->FillLoot return true. it wrong.
+ {
+ //subzone no result,use zone loot
+ fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true);
+ //use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks.
+ if (fishloot->empty())
+ fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true);
+ }
+}
+
+void GameObject::getFishLootJunk(Loot* fishloot, Player* loot_owner)
+{
+ fishloot->clear();
+
+ uint32 zone, subzone;
+ uint32 defaultzone = 1;
+ GetZoneAndAreaId(zone, subzone);
+
+ // if subzone loot exist use it
+ fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH);
+ if (fishloot->empty()) //use this becase if zone or subzone has normal mask drop, then fishloot->FillLoot return true.
+ {
+ //use zone loot
+ fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH);
+ if (fishloot->empty())
+ //use zone 1 as default
+ fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH);
+ }
}
void GameObject::SaveToDB()
@@ -1416,10 +1435,8 @@ void GameObject::Use(Unit* user)
else
player->SendLoot(GetGUID(), LOOT_FISHING);
}
- /// @todo else: junk
- else
- m_respawnTime = time(NULL);
-
+ else // else: junk
+ player->SendLoot(GetGUID(), LOOT_FISHING_JUNK);
break;
}
case GO_JUST_DEACTIVATED: // nothing to do, will be deleted at next update
@@ -1730,7 +1747,7 @@ void GameObject::Use(Unit* user)
CastSpell(user, spellId);
}
-void GameObject::CastSpell(Unit* target, uint32 spellId)
+void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /*= true*/)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
@@ -1749,7 +1766,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId)
if (self)
{
if (target)
- target->CastSpell(target, spellInfo, true);
+ target->CastSpell(target, spellInfo, triggered);
return;
}
@@ -1763,14 +1780,14 @@ void GameObject::CastSpell(Unit* target, uint32 spellId)
trigger->setFaction(owner->getFaction());
// needed for GO casts for proper target validation checks
trigger->SetOwnerGUID(owner->GetGUID());
- trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, owner->GetGUID());
+ trigger->CastSpell(target ? target : trigger, spellInfo, triggered, 0, 0, owner->GetGUID());
}
else
{
trigger->setFaction(14);
// Set owner guid for target if no owner available - needed by trigger auras
// - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell())
- trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, target ? target->GetGUID() : 0);
+ trigger->CastSpell(target ? target : trigger, spellInfo, triggered, 0, 0, target ? target->GetGUID() : 0);
}
}
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index a99c5db93aa..8f70fc0e907 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -713,6 +713,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map
void Refresh();
void Delete();
void getFishLoot(Loot* loot, Player* loot_owner);
+ void getFishLootJunk(Loot* loot, Player* loot_owner);
GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); }
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
@@ -790,7 +791,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map
GameObject* LookupFishingHoleAround(float range);
- void CastSpell(Unit* target, uint32 spell);
+ void CastSpell(Unit* target, uint32 spell, bool triggered = true);
void SendCustomAnim(uint32 anim);
bool IsInRange(float x, float y, float z, float radius) const;
diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h
index cc477c5bd37..bdf956f8921 100644
--- a/src/server/game/Entities/Item/ItemPrototype.h
+++ b/src/server/game/Entities/Item/ItemPrototype.h
@@ -734,7 +734,7 @@ struct ItemTemplate
default:
break;
}
- return itemLevel;
+ return std::max<float>(0.f, itemLevel);
}
bool IsPotion() const { return Class == ITEM_CLASS_CONSUMABLE && SubClass == ITEM_SUBCLASS_POTION; }
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index f2215fa2d6d..4ff0153dea8 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1163,6 +1163,9 @@ void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
{
if (IsInWorld())
RemoveFromWorld();
+
+ if (Transport* transport = GetTransport())
+ transport->RemovePassenger(this);
}
void WorldObject::_Create(uint32 guidlow, HighGuid guidhigh, uint32 phaseMask)
@@ -1215,7 +1218,7 @@ bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool
float sizefactor = GetObjectSize() + obj->GetObjectSize();
float maxdist = dist2compare + sizefactor;
- if (m_transport && obj->GetTransport() && obj->GetTransport()->GetGUIDLow() == m_transport->GetGUIDLow())
+ if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetGUIDLow() == GetTransport()->GetGUIDLow())
{
float dtx = m_movementInfo.transport.pos.m_positionX - obj->m_movementInfo.transport.pos.m_positionX;
float dty = m_movementInfo.transport.pos.m_positionY - obj->m_movementInfo.transport.pos.m_positionY;
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 768f5907c19..cc199969174 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -1916,6 +1916,8 @@ bool Pet::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint3
if (!InitEntry(Entry))
return false;
+ // Force regen flag for player pets, just like we do for players themselves
+ SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER);
SetSheath(SHEATH_STATE_MELEE);
return true;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index c7f36aff92b..8653106a865 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -26,6 +26,7 @@
#include "BattlefieldWG.h"
#include "Battleground.h"
#include "BattlegroundMgr.h"
+#include "BattlegroundScore.h"
#include "CellImpl.h"
#include "Channel.h"
#include "ChannelMgr.h"
@@ -2131,11 +2132,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
{
TC_LOG_DEBUG("maps", "Player %s using client without required expansion tried teleport to non accessible map %u", GetName().c_str(), mapid);
- if (GetTransport())
+ if (Transport* transport = GetTransport())
{
- m_transport->RemovePassenger(this);
- m_transport = NULL;
- m_movementInfo.transport.Reset();
+ transport->RemovePassenger(this);
RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
}
@@ -2153,16 +2152,12 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
SetUnitMovementFlags(GetUnitMovementFlags() & MOVEMENTFLAG_MASK_HAS_PLAYER_STATUS_OPCODE);
DisableSpline();
- if (m_transport)
+ if (Transport* transport = GetTransport())
{
if (options & TELE_TO_NOT_LEAVE_TRANSPORT)
AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
else
- {
- m_transport->RemovePassenger(this);
- m_transport = NULL;
- m_movementInfo.transport.Reset();
- }
+ transport->RemovePassenger(this);
}
// The player was ported to another map and loses the duel immediately.
@@ -2297,8 +2292,8 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// send transfer packets
WorldPacket data(SMSG_TRANSFER_PENDING, 4 + 4 + 4);
data << uint32(mapid);
- if (m_transport)
- data << m_transport->GetEntry() << GetMapId();
+ if (Transport* transport = GetTransport())
+ data << transport->GetEntry() << GetMapId();
GetSession()->SendPacket(&data);
}
@@ -2316,7 +2311,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
{
WorldPacket data(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4);
data << uint32(mapid);
- if (m_transport)
+ if (GetTransport())
data << m_movementInfo.transport.pos.PositionXYZOStream();
else
data << m_teleport_dest.PositionXYZOStream();
@@ -2926,11 +2921,10 @@ void Player::UninviteFromGroup()
void Player::RemoveFromGroup(Group* group, uint64 guid, RemoveMethod method /* = GROUP_REMOVEMETHOD_DEFAULT*/, uint64 kicker /* = 0 */, const char* reason /* = NULL */)
{
- if (group)
- {
- group->RemoveMember(guid, method, kicker, reason);
- group = NULL;
- }
+ if (!group)
+ return;
+
+ group->RemoveMember(guid, method, kicker, reason);
}
void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend, float /*group_rate*/)
@@ -6435,7 +6429,7 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal)
if (newVal < currVal)
UpdateSkillEnchantments(id, currVal, newVal);
// update step
- SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), MAKE_PAIR32(id, step));
+ SetUInt32Value(PLAYER_SKILL_INDEX(itr->second.pos), MAKE_PAIR32(id, step));
// update value
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), MAKE_SKILL_VALUE(newVal, maxVal));
if (itr->second.uState != SKILL_NEW)
@@ -8790,7 +8784,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
// not check distance for GO in case owned GO (fishing bobber case, for example)
// And permit out of range GO with no owner in case fishing hole
- if (!go || (loot_type != LOOT_FISHINGHOLE && (loot_type != LOOT_FISHING || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault()))
+ if (!go || (loot_type != LOOT_FISHINGHOLE && ((loot_type != LOOT_FISHING && loot_type != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault()))
{
SendLootRelease(guid);
return;
@@ -8828,6 +8822,8 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
if (loot_type == LOOT_FISHING)
go->getFishLoot(loot, this);
+ else if (loot_type == LOOT_FISHING_JUNK)
+ go->getFishLootJunk(loot, this);
if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules)
{
@@ -8974,9 +8970,9 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
if (loot_type == LOOT_PICKPOCKETING)
{
- if (!creature->lootForPickPocketed)
+ if (loot->loot_type != LOOT_PICKPOCKETING)
{
- creature->lootForPickPocketed = true;
+ creature->StartPickPocketRefillTimer();
loot->clear();
if (uint32 lootid = creature->GetCreatureTemplate()->pickpocketLootId)
@@ -8996,12 +8992,9 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
if (!recipient)
return;
- if (!creature->lootForBody)
+ if (loot->loot_type == LOOT_NONE)
{
- creature->lootForBody = true;
-
// for creature, loot is filled when creature is killed.
-
if (Group* group = recipient->GetGroup())
{
switch (group->GetLootMethod())
@@ -9022,11 +9015,17 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
}
}
- // possible only if creature->lootForBody && loot->empty() at spell cast check
- if (loot_type == LOOT_SKINNING)
+ // if loot is already skinning loot then don't do anything else
+ if (loot->loot_type == LOOT_SKINNING)
+ {
+ loot_type = LOOT_SKINNING;
+ permission = creature->GetSkinner() == GetGUID() ? OWNER_PERMISSION : NONE_PERMISSION;
+ }
+ else if (loot_type == LOOT_SKINNING)
{
loot->clear();
loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true);
+ creature->SetSkinner(GetGUID());
permission = OWNER_PERMISSION;
}
// set group rights only for loot_type != LOOT_SKINNING
@@ -9070,6 +9069,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
{
case LOOT_INSIGNIA: loot_type = LOOT_SKINNING; break;
case LOOT_FISHINGHOLE: loot_type = LOOT_FISHING; break;
+ case LOOT_FISHING_JUNK: loot_type = LOOT_FISHING; break;
default: break;
}
@@ -17398,15 +17398,15 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
{
uint64 transGUID = MAKE_NEW_GUID(transLowGUID, 0, HIGHGUID_MO_TRANSPORT);
+ Transport* transport = NULL;
if (GameObject* go = HashMapHolder<GameObject>::Find(transGUID))
- m_transport = go->ToTransport();
+ transport = go->ToTransport();
- if (m_transport)
+ if (transport)
{
- m_movementInfo.transport.guid = transGUID;
float x = fields[26].GetFloat(), y = fields[27].GetFloat(), z = fields[28].GetFloat(), o = fields[29].GetFloat();
m_movementInfo.transport.pos.Relocate(x, y, z, o);
- m_transport->CalculatePassengerPosition(x, y, z, &o);
+ transport->CalculatePassengerPosition(x, y, z, &o);
if (!Trinity::IsValidMapCoord(x, y, z, o) ||
// transport size limited
@@ -17417,7 +17417,6 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
TC_LOG_ERROR("entities.player", "Player (guidlow %d) have invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to bind location.",
guid, x, y, z, o);
- m_transport = NULL;
m_movementInfo.transport.Reset();
RelocateToHomebind();
@@ -17425,10 +17424,9 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
else
{
Relocate(x, y, z, o);
- mapId = m_transport->GetMapId();
+ mapId = transport->GetMapId();
- m_transport->AddPassenger(this);
- AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ transport->AddPassenger(this);
}
}
else
@@ -17836,6 +17834,9 @@ bool Player::isAllowedToLoot(const Creature* creature)
if (loot->isLooted()) // nothing to loot or everything looted.
return false;
+ if (loot->loot_type == LOOT_SKINNING)
+ return creature->GetSkinner() == GetGUID();
+
Group* thisGroup = GetGroup();
if (!thisGroup)
return this == creature->GetLootRecipient();
@@ -24981,7 +24982,7 @@ void Player::_LoadSkills(PreparedQueryResult result)
base_skill = 1; // skill mast be known and then > 0 in any case
if (GetPureSkillValue(SKILL_FIRST_AID) < base_skill)
- SetSkill(SKILL_FIRST_AID, 0, base_skill, base_skill);
+ SetSkill(SKILL_FIRST_AID, 4 /*artisan*/, base_skill, 300);
if (GetPureSkillValue(SKILL_AXES) < base_skill)
SetSkill(SKILL_AXES, 0, base_skill, base_skill);
if (GetPureSkillValue(SKILL_DEFENSE) < base_skill)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index aeac9db98aa..fdebbde0ae2 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -918,7 +918,7 @@ class PlayerTaxi
bool SetTaximaskNode(uint32 nodeidx)
{
uint8 field = uint8((nodeidx - 1) / 32);
- uint32 submask = 1 << ((nodeidx-1) % 32);
+ uint32 submask = 1 << ((nodeidx - 1) % 32);
if ((m_taximask[field] & submask) != submask)
{
m_taximask[field] |= submask;
@@ -951,7 +951,7 @@ class PlayerTaxi
std::deque<uint32> m_TaxiDestinations;
};
-std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi);
+std::ostringstream& operator << (std::ostringstream& ss, PlayerTaxi const& taxi);
class Player;
@@ -2635,8 +2635,8 @@ class Player : public Unit, public GridObject<Player>
uint32 _activeCheats;
};
-void AddItemsSetItem(Player*player, Item* item);
-void RemoveItemsSetItem(Player*player, ItemTemplate const* proto);
+void AddItemsSetItem(Player* player, Item* item);
+void RemoveItemsSetItem(Player* player, ItemTemplate const* proto);
// "the bodies of template functions must be made available in a header file"
template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell* spell)
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index 8bc07732bb6..d907274f8d1 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -35,7 +35,7 @@
Transport::Transport() : GameObject(),
_transportInfo(NULL), _isMoving(true), _pendingStop(false),
- _triggeredArrivalEvent(false), _triggeredDepartureEvent(false)
+ _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengerTeleportItr(_passengers.begin())
{
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
}
@@ -107,9 +107,6 @@ void Transport::CleanupsBeforeDelete(bool finalCleanup /*= true*/)
while (!_passengers.empty())
{
WorldObject* obj = *_passengers.begin();
- obj->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
- obj->m_movementInfo.transport.Reset();
- obj->SetTransport(NULL);
RemovePassenger(obj);
}
@@ -231,6 +228,9 @@ void Transport::AddPassenger(WorldObject* passenger)
if (_passengers.insert(passenger).second)
{
+ passenger->SetTransport(this);
+ passenger->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ passenger->m_movementInfo.transport.guid = GetGUID();
TC_LOG_DEBUG("entities.transport", "Object %s boarded transport %s.", passenger->GetName().c_str(), GetName().c_str());
if (Player* plr = passenger->ToPlayer())
@@ -240,8 +240,27 @@ void Transport::AddPassenger(WorldObject* passenger)
void Transport::RemovePassenger(WorldObject* passenger)
{
- if (_passengers.erase(passenger) || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload
+ bool erased = false;
+ if (_passengerTeleportItr != _passengers.end())
{
+ PassengerSet::iterator itr = _passengers.find(passenger);
+ if (itr != _passengers.end())
+ {
+ if (itr == _passengerTeleportItr)
+ ++_passengerTeleportItr;
+
+ _passengers.erase(itr);
+ erased = true;
+ }
+ }
+ else
+ erased = _passengers.erase(passenger) > 0;
+
+ if (erased || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload
+ {
+ passenger->SetTransport(NULL);
+ passenger->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ passenger->m_movementInfo.transport.Reset();
TC_LOG_DEBUG("entities.transport", "Object %s removed from transport %s.", passenger->GetName().c_str(), GetName().c_str());
if (Player* plr = passenger->ToPlayer())
@@ -570,9 +589,9 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
GetMap()->RemoveFromMap<Transport>(this, false);
SetMap(newMap);
- for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end();)
+ for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();)
{
- WorldObject* obj = (*itr++);
+ WorldObject* obj = (*_passengerTeleportItr++);
float destX, destY, destZ, destO;
obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
@@ -595,7 +614,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
}
case TYPEID_PLAYER:
if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
- _passengers.erase(obj);
+ RemovePassenger(obj);
break;
case TYPEID_DYNAMICOBJECT:
obj->AddObjectToRemoveList();
@@ -613,7 +632,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
else
{
// Teleport players, they need to know it
- for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
+ for (PassengerSet::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
{
if ((*itr)->GetTypeId() == TYPEID_PLAYER)
{
@@ -630,9 +649,9 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
}
}
-void Transport::UpdatePassengerPositions(std::set<WorldObject*>& passengers)
+void Transport::UpdatePassengerPositions(PassengerSet& passengers)
{
- for (std::set<WorldObject*>::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
+ for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
{
WorldObject* passenger = *itr;
// transport teleported but passenger not yet (can happen for players)
diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h
index 293d4334a2e..e644417f1ac 100644
--- a/src/server/game/Entities/Transport/Transport.h
+++ b/src/server/game/Entities/Transport/Transport.h
@@ -31,6 +31,8 @@ class Transport : public GameObject, public TransportBase
Transport();
public:
+ typedef std::set<WorldObject*> PassengerSet;
+
~Transport();
bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress);
@@ -42,7 +44,7 @@ class Transport : public GameObject, public TransportBase
void AddPassenger(WorldObject* passenger);
void RemovePassenger(WorldObject* passenger);
- std::set<WorldObject*> const& GetPassengers() const { return _passengers; }
+ PassengerSet const& GetPassengers() const { return _passengers; }
Creature* CreateNPCPassenger(uint32 guid, CreatureData const* data);
GameObject* CreateGOPassenger(uint32 guid, GameObjectData const* data);
@@ -99,7 +101,7 @@ class Transport : public GameObject, public TransportBase
void MoveToNextWaypoint();
float CalculateSegmentPos(float perc);
bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o);
- void UpdatePassengerPositions(std::set<WorldObject*>& passengers);
+ void UpdatePassengerPositions(PassengerSet& passengers);
void DoEventIfAny(KeyFrame const& node, bool departure);
//! Helpers to know if stop frame was reached
@@ -118,8 +120,9 @@ class Transport : public GameObject, public TransportBase
bool _triggeredArrivalEvent;
bool _triggeredDepartureEvent;
- std::set<WorldObject*> _passengers;
- std::set<WorldObject*> _staticPassengers;
+ PassengerSet _passengers;
+ PassengerSet::iterator _passengerTeleportItr;
+ PassengerSet _staticPassengers;
};
#endif
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 2b6cb9dd8ba..ca4780b787e 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -21,6 +21,7 @@
#include "Battlefield.h"
#include "BattlefieldMgr.h"
#include "Battleground.h"
+#include "BattlegroundScore.h"
#include "CellImpl.h"
#include "ConditionMgr.h"
#include "CreatureAI.h"
@@ -3352,7 +3353,7 @@ void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex)
AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID());
ASSERT(aurApp);
if (!aurApp->GetEffectMask())
- _ApplyAura(aurApp, 1<<effIndex);
+ _ApplyAura(aurApp, 1 << effIndex);
else
aurApp->_HandleEffect(effIndex, true);
}
@@ -3390,7 +3391,7 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask)
// apply effects of the aura
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (effMask & 1<<i && (!aurApp->GetRemoveMode()))
+ if (effMask & 1 << i && (!aurApp->GetRemoveMode()))
aurApp->_HandleEffect(i, true);
}
}
@@ -3503,6 +3504,19 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura)
if (spellProto->IsPassiveStackableWithRanks())
return;
+ if (!IsHighestExclusiveAura(aura))
+ {
+ if (!aura->GetSpellInfo()->IsAffectingArea())
+ {
+ Unit* caster = aura->GetCaster();
+ if (caster && caster->GetTypeId() == TYPEID_PLAYER)
+ Spell::SendCastResult(caster->ToPlayer(), aura->GetSpellInfo(), 1, SPELL_FAILED_AURA_BOUNCED);
+ }
+
+ RemoveAura(aura);
+ return;
+ }
+
bool remove = false;
for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
{
@@ -3832,6 +3846,7 @@ void Unit::RemoveAurasByType(AuraType auraType, uint64 casterGUID, Aura* except,
{
Aura* aura = (*iter)->GetBase();
AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID());
+ ASSERT(aurApp);
++iter;
if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
@@ -6036,11 +6051,11 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
triggered_spell_id = 34299;
if (triggeredByAura->GetCasterGUID() != GetGUID())
break;
- int32 basepoints1 = triggerAmount * 2;
+ int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2);
// Improved Leader of the Pack
// Check cooldown of heal spell cooldown
if (GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299))
- CastCustomSpell(this, 60889, &basepoints1, 0, 0, true, 0, triggeredByAura);
+ CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura);
break;
}
// Healing Touch (Dreamwalker Raiment set)
@@ -8645,25 +8660,30 @@ void Unit::setPowerType(Powers new_powertype)
}
}
+ float powerMultiplier = 1.0f;
+ if (!IsPet())
+ if (Creature* creature = ToCreature())
+ powerMultiplier = creature->GetCreatureTemplate()->ModMana;
+
switch (new_powertype)
{
default:
case POWER_MANA:
break;
case POWER_RAGE:
- SetMaxPower(POWER_RAGE, GetCreatePowers(POWER_RAGE));
+ SetMaxPower(POWER_RAGE, uint32(std::ceil(GetCreatePowers(POWER_RAGE) * powerMultiplier)));
SetPower(POWER_RAGE, 0);
break;
case POWER_FOCUS:
- SetMaxPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS));
- SetPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS));
+ SetMaxPower(POWER_FOCUS, uint32(std::ceil(GetCreatePowers(POWER_FOCUS) * powerMultiplier)));
+ SetPower(POWER_FOCUS, uint32(std::ceil(GetCreatePowers(POWER_FOCUS) * powerMultiplier)));
break;
case POWER_ENERGY:
- SetMaxPower(POWER_ENERGY, GetCreatePowers(POWER_ENERGY));
+ SetMaxPower(POWER_ENERGY, uint32(std::ceil(GetCreatePowers(POWER_ENERGY) * powerMultiplier)));
break;
case POWER_HAPPINESS:
- SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS));
- SetPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS));
+ SetMaxPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier)));
+ SetPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier)));
break;
}
}
@@ -10486,17 +10506,21 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
{
if (!((*i)->IsAffectedOnSpell(spellProto)))
continue;
- int32 modChance = 0;
+
switch ((*i)->GetMiscValue())
{
- // Shatter
- case 911: modChance+= 16;
- case 910: modChance+= 17;
- case 849: modChance+= 17;
- if (!victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
- break;
- crit_chance+=modChance;
+ case 911: // Shatter (Rank 1)
+ if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
+ crit_chance += 17;
break;
+ case 910: // Shatter (Rank 2)
+ if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
+ crit_chance += 34;
+ break;
+ case 849: // Shatter (Rank 3)
+ if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
+ crit_chance += 50;
+ break;
case 7917: // Glyph of Shadowburn
if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
crit_chance+=(*i)->GetAmount();
@@ -10516,7 +10540,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
case SPELLFAMILY_MAGE:
// Glyph of Fire Blast
if (spellProto->SpellFamilyFlags[0] == 0x2 && spellProto->SpellIconID == 12)
- if (victim->HasAuraWithMechanic((1<<MECHANIC_STUN) | (1<<MECHANIC_KNOCKOUT)))
+ if (victim->HasAuraWithMechanic((1 << MECHANIC_STUN) | (1 << MECHANIC_KNOCKOUT)))
if (AuraEffect const* aurEff = GetAuraEffect(56369, EFFECT_0))
crit_chance += aurEff->GetAmount();
break;
@@ -10537,7 +10561,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
crit_chance += aurEff->GetAmount();
break;
}
- break;
+ break;
case SPELLFAMILY_ROGUE:
// Shiv-applied poisons can't crit
if (FindCurrentSpellBySpellId(5938))
@@ -10559,7 +10583,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
return 100.0f;
break;
}
- break;
+ break;
case SPELLFAMILY_SHAMAN:
// Lava Burst
if (spellProto->SpellFamilyFlags[1] & 0x00001000)
@@ -10569,7 +10593,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
return 100.0f;
break;
}
- break;
+ break;
}
}
break;
@@ -10590,17 +10614,17 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
crit_chance += rendAndTear->GetAmount();
break;
}
- break;
+ break;
case SPELLFAMILY_WARRIOR:
- // Victory Rush
- if (spellProto->SpellFamilyFlags[1] & 0x100)
- {
- // Glyph of Victory Rush
- if (AuraEffect const* aurEff = GetAuraEffect(58382, 0))
- crit_chance += aurEff->GetAmount();
- break;
- }
- break;
+ // Victory Rush
+ if (spellProto->SpellFamilyFlags[1] & 0x100)
+ {
+ // Glyph of Victory Rush
+ if (AuraEffect const* aurEff = GetAuraEffect(58382, 0))
+ crit_chance += aurEff->GetAmount();
+ break;
+ }
+ break;
}
}
/// Intentional fallback. Calculate critical strike chance for both Ranged and Melee spells
@@ -12883,19 +12907,24 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in
return std::max(duration, 0);
}
-void Unit::ModSpellCastTime(SpellInfo const* spellProto, int32 & castTime, Spell* spell)
+void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell* spell)
{
- if (!spellProto || castTime < 0)
+ if (!spellInfo || castTime < 0)
+ return;
+
+ if (spellInfo->IsChanneled() && !(spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION))
return;
+
// called from caster
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CASTING_TIME, castTime, spell);
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
- if (!(spellProto->Attributes & (SPELL_ATTR0_ABILITY|SPELL_ATTR0_TRADESPELL)) && ((GetTypeId() == TYPEID_PLAYER && spellProto->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
+ if (!((spellInfo->Attributes & (SPELL_ATTR0_ABILITY | SPELL_ATTR0_TRADESPELL)) || (spellInfo->AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS)) &&
+ ((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
castTime = int32(float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED));
- else if (spellProto->Attributes & SPELL_ATTR0_REQ_AMMO && !(spellProto->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG))
+ else if (spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO && !(spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG))
castTime = int32(float(castTime) * m_modAttackSpeedPct[RANGED_ATTACK]);
- else if (spellProto->SpellVisual[0] == 3881 && HasAura(67556)) // cooking with Chef Hat.
+ else if (spellInfo->SpellVisual[0] == 3881 && HasAura(67556)) // cooking with Chef Hat.
castTime = 500;
}
@@ -13550,12 +13579,7 @@ void Unit::CleanupsBeforeDelete(bool finalCleanup)
{
CleanupBeforeRemoveFromMap(finalCleanup);
- if (GetTransport())
- {
- GetTransport()->RemovePassenger(this);
- SetTransport(NULL);
- m_movementInfo.transport.Reset();
- }
+ WorldObject::CleanupsBeforeDelete(finalCleanup);
}
void Unit::UpdateCharmAI()
@@ -15247,8 +15271,8 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
if (creature)
{
Loot* loot = &creature->loot;
- if (creature->lootForPickPocketed)
- creature->lootForPickPocketed = false;
+ if (creature->loot.loot_type == LOOT_PICKPOCKETING)
+ creature->ResetPickPocketRefillTimer();
loot->clear();
if (uint32 lootid = creature->GetCreatureTemplate()->lootid)
@@ -15367,9 +15391,12 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
if (!creature->IsPet())
{
creature->DeleteThreatList();
- CreatureTemplate const* cInfo = creature->GetCreatureTemplate();
- if (cInfo && (cInfo->lootid || cInfo->maxgold > 0))
+
+ // must be after setDeathState which resets dynamic flags
+ if (!creature->loot.empty())
creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+ else
+ creature->AllLootRemovedFromCorpse();
}
// Call KilledUnit for creatures, this needs to be called after the lootable flag is set
@@ -16354,19 +16381,25 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
}
}
- WorldObject::SetPhaseMask(newPhaseMask, update);
+ // Phase player, dont update
+ WorldObject::SetPhaseMask(newPhaseMask, false);
- if (!IsInWorld())
- return;
+ // Phase pets and summons
+ if (IsInWorld())
+ {
+ for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
+ if ((*itr)->GetTypeId() == TYPEID_UNIT)
+ (*itr)->SetPhaseMask(newPhaseMask, true);
- for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
- if ((*itr)->GetTypeId() == TYPEID_UNIT)
- (*itr)->SetPhaseMask(newPhaseMask, true);
+ for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
+ if (m_SummonSlot[i])
+ if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
+ summon->SetPhaseMask(newPhaseMask, true);
+ }
- for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
- if (m_SummonSlot[i])
- if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
- summon->SetPhaseMask(newPhaseMask, true);
+ // Update visibility after phasing pets and summons so they wont despawn
+ if (update)
+ UpdateObjectVisibility();
}
void Unit::UpdateObjectVisibility(bool forced)
@@ -17742,3 +17775,73 @@ void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns c
data << uint32(itr->second);
}
}
+
+int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
+{
+ int32 val = 0;
+ SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id);
+ for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr)
+ {
+ if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
+ {
+ AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType);
+ for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr)
+ {
+ if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) &&
+ sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second))
+ {
+ // absolute value only
+ if (abs(val) < abs((*auraItr)->GetAmount()))
+ val = (*auraItr)->GetAmount();
+ }
+ }
+ }
+ }
+ return val;
+}
+
+bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/)
+{
+ for (uint32 i = 0 ; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (AuraEffect const* aurEff = aura->GetEffect(i))
+ {
+ AuraType const auraType = AuraType(aura->GetSpellInfo()->Effects[i].ApplyAuraName);
+ AuraEffectList const& auras = GetAuraEffectsByType(auraType);
+ for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();)
+ {
+ AuraEffect const* existingAurEff = (*itr);
+ ++itr;
+
+ if (sSpellMgr->CheckSpellGroupStackRules(aura->GetSpellInfo(), existingAurEff->GetSpellInfo())
+ == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST)
+ {
+ int32 diff = abs(aurEff->GetAmount()) - abs(existingAurEff->GetAmount());
+ if (!diff)
+ diff = int32(aura->GetEffectMask()) - int32(existingAurEff->GetBase()->GetEffectMask());
+
+ if (diff > 0)
+ {
+ Aura const* base = existingAurEff->GetBase();
+ // no removing of area auras from the original owner, as that completely cancels them
+ if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this))
+ {
+ if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID()))
+ {
+ bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType);
+ uint32 removedAuras = m_removedAurasCount;
+ RemoveAura(aurApp);
+ if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1)
+ itr = auras.begin();
+ }
+ }
+ }
+ else if (diff < 0)
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index dbb463585f0..535d75af204 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1289,7 +1289,7 @@ class Unit : public WorldObject
void RemoveFromWorld();
void CleanupBeforeRemoveFromMap(bool finalCleanup);
- void CleanupsBeforeDelete(bool finalCleanup = true); // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units)
+ void CleanupsBeforeDelete(bool finalCleanup = true) override; // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units)
DiminishingLevels GetDiminishing(DiminishingGroup group);
void IncrDiminishing(DiminishingGroup group);
@@ -2155,6 +2155,9 @@ class Unit : public WorldObject
time_t GetLastDamagedTime() const { return _lastDamagedTime; }
void SetLastDamagedTime(time_t val) { _lastDamagedTime = val; }
+ int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue = false, int32 miscValue = 0) const;
+ bool IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications = false);
+
protected:
explicit Unit (bool isWorldObject);
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 4c3724a8860..915e6016e22 100755
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -77,8 +77,12 @@ Vehicle::~Vehicle()
void Vehicle::Install()
{
if (_me->GetTypeId() == TYPEID_UNIT)
+ {
if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(_vehicleInfo->m_powerDisplayId))
_me->setPowerType(Powers(powerDisplay->PowerType));
+ else if (_me->getClass() == CLASS_ROGUE)
+ _me->setPowerType(POWER_ENERGY);
+ }
_status = STATUS_INSTALLED;
if (GetBase()->GetTypeId() == TYPEID_UNIT)
@@ -775,6 +779,8 @@ bool VehicleJoinEvent::Execute(uint64, uint32)
Passenger->InterruptNonMeleeSpells(false);
Passenger->RemoveAurasByType(SPELL_AURA_MOUNTED);
+ VehicleSeatEntry const* veSeat = Seat->second.SeatInfo;
+
Player* player = Passenger->ToPlayer();
if (player)
{
@@ -785,14 +791,14 @@ bool VehicleJoinEvent::Execute(uint64, uint32)
player->StopCastingCharm();
player->StopCastingBindSight();
player->SendOnCancelExpectedVehicleRideAura();
- player->UnsummonPetTemporaryIfAny();
+ if (!(veSeat->m_flagsB & VEHICLE_SEAT_FLAG_B_KEEP_PET))
+ player->UnsummonPetTemporaryIfAny();
}
if (Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE)
Passenger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
Passenger->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
- VehicleSeatEntry const* veSeat = Seat->second.SeatInfo;
Passenger->m_movementInfo.transport.pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
Passenger->m_movementInfo.transport.time = 0;
Passenger->m_movementInfo.transport.seat = Seat->first;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 207f80eabe7..9eb7d5ec1bf 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1668,7 +1668,7 @@ void ObjectMgr::LoadCreatures()
}
// Skip spawnMask check for transport maps
- if (!_transportMaps.count(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid])
+ if (!IsTransportMap(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid])
TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u).", guid, data.spawnMask, data.mapid);
bool ok = true;
@@ -2003,7 +2003,7 @@ void ObjectMgr::LoadGameobjects()
data.spawnMask = fields[14].GetUInt8();
- if (!_transportMaps.count(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid])
+ if (!IsTransportMap(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid])
TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) that has wrong spawn mask %u including not supported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapid);
data.phaseMask = fields[15].GetUInt32();
@@ -2951,32 +2951,32 @@ void ObjectMgr::LoadVehicleTemplateAccessories()
{
Field* fields = result->Fetch();
- uint32 uiEntry = fields[0].GetUInt32();
- uint32 uiAccessory = fields[1].GetUInt32();
- int8 uiSeat = int8(fields[2].GetInt8());
- bool bMinion = fields[3].GetBool();
- uint8 uiSummonType = fields[4].GetUInt8();
- uint32 uiSummonTimer= fields[5].GetUInt32();
+ uint32 entry = fields[0].GetUInt32();
+ uint32 accessory = fields[1].GetUInt32();
+ int8 seatId = fields[2].GetInt8();
+ bool isMinion = fields[3].GetBool();
+ uint8 summonType = fields[4].GetUInt8();
+ uint32 summonTimer = fields[5].GetUInt32();
- if (!sObjectMgr->GetCreatureTemplate(uiEntry))
+ if (!sObjectMgr->GetCreatureTemplate(entry))
{
- TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u does not exist.", uiEntry);
+ TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u does not exist.", entry);
continue;
}
- if (!sObjectMgr->GetCreatureTemplate(uiAccessory))
+ if (!sObjectMgr->GetCreatureTemplate(accessory))
{
- TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: Accessory %u does not exist.", uiAccessory);
+ TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: Accessory %u does not exist.", accessory);
continue;
}
- if (_spellClickInfoStore.find(uiEntry) == _spellClickInfoStore.end())
+ if (_spellClickInfoStore.find(entry) == _spellClickInfoStore.end())
{
- TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u has no data in npc_spellclick_spells", uiEntry);
+ TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u has no data in npc_spellclick_spells", entry);
continue;
}
- _vehicleTemplateAccessoryStore[uiEntry].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion, uiSummonType, uiSummonTimer));
+ _vehicleTemplateAccessoryStore[entry].push_back(VehicleAccessory(accessory, seatId, isMinion, summonType, summonTimer));
++count;
}
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index ba5940d7e12..e5e55b847d3 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -1293,6 +1293,8 @@ class ObjectMgr
void LoadFactionChangeSpells();
void LoadFactionChangeTitles();
+ bool IsTransportMap(uint32 mapId) const { return _transportMaps.count(mapId); }
+
private:
// first free id for selected id type
uint32 _auctionId;
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
index 472497ea5f2..270d598d53a 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
@@ -35,7 +35,8 @@ void VisibleNotifier::SendToSelf()
// at this moment i_clientGUIDs have guids that not iterate at grid level checks
// but exist one case when this possible and object not out of range: transports
if (Transport* transport = i_player.GetTransport())
- for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end();++itr)
+ {
+ for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
{
if (vis_guids.find((*itr)->GetGUID()) != vis_guids.end())
{
@@ -54,11 +55,15 @@ void VisibleNotifier::SendToSelf()
case TYPEID_UNIT:
i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow);
break;
+ case TYPEID_DYNAMICOBJECT:
+ i_player.UpdateVisibilityOf((*itr)->ToDynObject(), i_data, i_visibleNow);
+ break;
default:
break;
}
}
}
+ }
for (Player::ClientGUIDs::const_iterator it = vis_guids.begin();it != vis_guids.end(); ++it)
{
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 113df993f81..45ecbf0c3df 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1572,7 +1572,7 @@ void Group::UpdatePlayerOutOfRange(Player* player)
for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
member = itr->GetSource();
- if (member && !member->IsWithinDist(player, member->GetSightRange(), false))
+ if (member && member != player && (!member->IsInMap(player) || !member->IsWithinDist(player, member->GetSightRange(), false)))
member->GetSession()->SendPacket(&data);
}
}
diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp
index 0dfe396b65a..7def6b0f467 100644
--- a/src/server/game/Handlers/BattleGroundHandler.cpp
+++ b/src/server/game/Handlers/BattleGroundHandler.cpp
@@ -309,7 +309,7 @@ void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recvData*/)
return;
WorldPacket data;
- sBattlegroundMgr->BuildPvpLogDataPacket(&data, bg);
+ bg->BuildPvPLogDataPacket(data);
SendPacket(&data);
TC_LOG_DEBUG("network", "WORLD: Sent MSG_PVP_LOG_DATA Message");
diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp
index 0a797f0e008..dd654fb3ad0 100644
--- a/src/server/game/Handlers/CalendarHandler.cpp
+++ b/src/server/game/Handlers/CalendarHandler.cpp
@@ -260,26 +260,43 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData)
}
else
{
+ // client limits the amount of players to be invited to 100
+ const uint32 MaxPlayerInvites = 100;
+
uint32 inviteCount;
- recvData >> inviteCount;
+ uint64 invitee[MaxPlayerInvites];
+ uint8 status[MaxPlayerInvites];
+ uint8 rank[MaxPlayerInvites];
+
+ memset(invitee, 0, sizeof(invitee));
+ memset(status, 0, sizeof(status));
+ memset(rank, 0, sizeof(rank));
+
+ try
+ {
+ recvData >> inviteCount;
+
+ for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i)
+ {
+ recvData.readPackGUID(invitee[i]);
+ recvData >> status[i] >> rank[i];
+ }
+ }
+ catch (ByteBufferException const&)
+ {
+ delete calendarEvent;
+ calendarEvent = NULL;
+ throw;
+ }
SQLTransaction trans;
if (inviteCount > 1)
trans = CharacterDatabase.BeginTransaction();
- // client limits the amount of players to be invited to 100
- const uint32 MaxPlayerInvites = 100;
-
for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i)
{
- uint64 invitee = 0;
- uint8 status = 0;
- uint8 rank = 0;
- recvData.readPackGUID(invitee);
- recvData >> status >> rank;
-
// 946684800 is 01/01/2000 00:00:00 - default response time
- CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), invitee, guid, 946684800, CalendarInviteStatus(status), CalendarModerationRank(rank), "");
+ CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), invitee[i], guid, 946684800, CalendarInviteStatus(status[i]), CalendarModerationRank(rank[i]), "");
sCalendarMgr->AddInvite(calendarEvent, invite, trans);
}
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index d4af17ca78b..9ad382b4686 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -696,10 +696,15 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData)
{
uint64 guid;
recvData >> guid;
+ // Initiating
+ uint32 initAccountId = GetAccountId();
// can't delete loaded character
if (ObjectAccessor::FindPlayer(guid))
+ {
+ sScriptMgr->OnPlayerFailedDelete(guid, initAccountId);
return;
+ }
uint32 accountId = 0;
uint8 level = 0;
@@ -708,6 +713,7 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData)
// is guild leader
if (sGuildMgr->GetGuildByLeader(guid))
{
+ sScriptMgr->OnPlayerFailedDelete(guid, initAccountId);
WorldPacket data(SMSG_CHAR_DELETE, 1);
data << uint8(CHAR_DELETE_FAILED_GUILD_LEADER);
SendPacket(&data);
@@ -717,6 +723,7 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData)
// is arena team captain
if (sArenaTeamMgr->GetArenaTeamByCaptain(guid))
{
+ sScriptMgr->OnPlayerFailedDelete(guid, initAccountId);
WorldPacket data(SMSG_CHAR_DELETE, 1);
data << uint8(CHAR_DELETE_FAILED_ARENA_CAPTAIN);
SendPacket(&data);
@@ -735,12 +742,18 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData)
}
// prevent deleting other players' characters using cheating tools
- if (accountId != GetAccountId())
+ if (accountId != initAccountId)
+ {
+ sScriptMgr->OnPlayerFailedDelete(guid, initAccountId);
return;
+ }
std::string IP_str = GetRemoteAddress();
TC_LOG_INFO("entities.player.character", "Account: %d, IP: %s deleted character: %s, GUID: %u, Level: %u", accountId, IP_str.c_str(), name.c_str(), GUID_LOPART(guid), level);
- sScriptMgr->OnPlayerDelete(guid);
+
+ // To prevent hook failure, place hook before removing reference from DB
+ sScriptMgr->OnPlayerDelete(guid, initAccountId); // To prevent race conditioning, but as it also makes sense, we hand the accountId over for successful delete.
+ // Shouldn't interfere with character deletion though
if (sLog->ShouldLog("entities.player.dump", LOG_LEVEL_INFO)) // optimize GetPlayerDump call
{
@@ -1001,7 +1014,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
SendNotification(LANG_RESET_TALENTS);
}
- if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST))
+ bool firstLogin = pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST);
+ if (firstLogin)
pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST);
// show time before shutdown if shutdown planned.
@@ -1026,7 +1040,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
// Handle Login-Achievements (should be handled after loading)
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN, 1);
- sScriptMgr->OnPlayerLogin(pCurrChar);
+ sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin);
+
delete holder;
}
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index 3ef99cc2fc1..60966ace011 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -1443,6 +1443,10 @@ void WorldSession::HandleItemRefund(WorldPacket &recvData)
return;
}
+ // Don't try to refund item currently being disenchanted
+ if (_player->GetLootGUID() == guid)
+ return;
+
GetPlayer()->RefundItem(item);
}
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index f92c6e08e31..b9c6f349ac3 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -81,7 +81,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
{
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
- bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed);
+ bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
{
@@ -148,7 +148,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
case HIGHGUID_VEHICLE:
{
Creature* creature = player->GetMap()->GetCreature(guid);
- bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed);
+ bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE))
{
loot = &creature->loot;
@@ -338,7 +338,8 @@ void WorldSession::DoLootRelease(uint64 lguid)
}
else
{
- if (pItem->loot.isLooted()) // Only delete item if no loot or money (unlooted loot is saved to db)
+ // Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item
+ if (pItem->loot.isLooted() || !(proto->Flags & ITEM_PROTO_FLAG_OPENABLE))
player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
}
return; // item can be looted only single player
@@ -347,18 +348,19 @@ void WorldSession::DoLootRelease(uint64 lguid)
{
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
- bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed);
+ bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
return;
loot = &creature->loot;
if (loot->isLooted())
{
+ creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+
// skip pickpocketing loot for speed, skinning timer reduction is no-op in fact
if (!creature->IsAlive())
creature->AllLootRemovedFromCorpse();
- creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
loot->clear();
}
else
diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp
index 10ef7810d1d..326d198903e 100644
--- a/src/server/game/Handlers/MailHandler.cpp
+++ b/src/server/game/Handlers/MailHandler.cpp
@@ -131,6 +131,13 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
uint32 reqmoney = cost + money;
+ // Check for overflow
+ if (reqmoney < money)
+ {
+ player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY);
+ return;
+ }
+
if (!player->HasEnoughMoney(reqmoney) && !player->IsGameMaster())
{
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY);
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index cef414163bd..6fedc481a14 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -285,7 +285,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
}
/* handle special cases */
- if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT)
+ if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT))
{
// transports size limited
// (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped)
@@ -308,27 +308,15 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
if (!plrMover->GetTransport())
{
if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
- {
- plrMover->m_transport = transport;
transport->AddPassenger(plrMover);
- }
}
else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid)
{
- bool foundNewTransport = false;
- plrMover->m_transport->RemovePassenger(plrMover);
+ plrMover->GetTransport()->RemovePassenger(plrMover);
if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
- {
- foundNewTransport = true;
- plrMover->m_transport = transport;
transport->AddPassenger(plrMover);
- }
-
- if (!foundNewTransport)
- {
- plrMover->m_transport = NULL;
+ else
movementInfo.transport.Reset();
- }
}
}
@@ -336,13 +324,12 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
{
GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid);
if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT)
- movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT;
+ movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
}
}
else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave
{
- plrMover->m_transport->RemovePassenger(plrMover);
- plrMover->m_transport = NULL;
+ plrMover->GetTransport()->RemovePassenger(plrMover);
movementInfo.transport.Reset();
}
diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp
index f90dfef2684..8a94753b692 100644
--- a/src/server/game/Handlers/SkillHandler.cpp
+++ b/src/server/game/Handlers/SkillHandler.cpp
@@ -98,7 +98,8 @@ void WorldSession::HandleUnlearnSkillOpcode(WorldPacket& recvData)
uint32 skillId;
recvData >> skillId;
- if (!IsPrimaryProfessionSkill(skillId))
+ SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skillId, GetPlayer()->getRace(), GetPlayer()->getClass());
+ if (!rcEntry || !(rcEntry->Flags & SKILL_FLAG_UNLEARNABLE))
return;
GetPlayer()->SetSkill(skillId, 0, 0, 0);
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index ed0f3b9717b..cb3b9082c20 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -76,6 +76,8 @@ enum PermissionTypes
enum LootType
{
+ LOOT_NONE = 0,
+
LOOT_CORPSE = 1,
LOOT_PICKPOCKETING = 2,
LOOT_FISHING = 3,
@@ -86,7 +88,8 @@ enum LootType
LOOT_MILLING = 8,
LOOT_FISHINGHOLE = 20, // unsupported by client, sending LOOT_FISHING instead
- LOOT_INSIGNIA = 21 // unsupported by client, sending LOOT_CORPSE instead
+ LOOT_INSIGNIA = 21, // unsupported by client, sending LOOT_CORPSE instead
+ LOOT_FISHING_JUNK = 22 // unsupported by client, sending LOOT_FISHING instead
};
// type of Loot Item in Loot View
@@ -340,6 +343,7 @@ struct Loot
gold = 0;
unlootedCount = 0;
roundRobinPlayer = 0;
+ loot_type = LOOT_NONE;
i_LootValidatorRefManager.clearReferences();
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index d3be33cb441..01e3af149dc 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2506,15 +2506,9 @@ void Map::SendInitSelf(Player* player)
// build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
if (Transport* transport = player->GetTransport())
- {
- for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
- {
+ for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
if (player != (*itr) && player->HaveAtClient(*itr))
- {
(*itr)->BuildCreateUpdateBlockForPlayer(&data, player);
- }
- }
- }
WorldPacket packet;
data.BuildPacket(&packet);
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 34871085157..3a680e30217 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -1224,7 +1224,8 @@ enum TrinityStrings
LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD = 11006,
LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD = 11007,
- LANG_NPCINFO_INHABIT_TYPE = 11008
+ LANG_NPCINFO_INHABIT_TYPE = 11008,
+ LANG_NPCINFO_FLAGS_EXTRA = 11009
// NOT RESERVED IDS 12000-1999999999
// `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID)
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 4ec1d5750a4..77bc76c6dfd 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -41,7 +41,8 @@ enum LootModes
LOOT_MODE_HARD_MODE_1 = 0x2,
LOOT_MODE_HARD_MODE_2 = 0x4,
LOOT_MODE_HARD_MODE_3 = 0x8,
- LOOT_MODE_HARD_MODE_4 = 0x10
+ LOOT_MODE_HARD_MODE_4 = 0x10,
+ LOOT_MODE_JUNK_FISH = 0x8000
};
enum Expansions
@@ -396,7 +397,7 @@ enum SpellAttr3
SPELL_ATTR3_MAIN_HAND = 0x00000400, // 10 Main hand weapon required
SPELL_ATTR3_BATTLEGROUND = 0x00000800, // 11 Can only be cast in battleground
SPELL_ATTR3_ONLY_TARGET_GHOSTS = 0x00001000, // 12
- SPELL_ATTR3_UNK13 = 0x00002000, // 13
+ SPELL_ATTR3_DONT_DISPLAY_CHANNEL_BAR = 0x00002000, // 13 Clientside attribute - will not display channeling bar
SPELL_ATTR3_IS_HONORLESS_TARGET = 0x00004000, // 14 "Honorless Target" only this spells have this flag
SPELL_ATTR3_UNK15 = 0x00008000, // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag
SPELL_ATTR3_CANT_TRIGGER_PROC = 0x00010000, // 16 confirmed with many patchnotes
@@ -543,7 +544,7 @@ enum SpellAttr7
SPELL_ATTR7_UNK13 = 0x00002000, // 13 Not set in 3.2.2a.
SPELL_ATTR7_UNK14 = 0x00004000, // 14 Only 52150 (Raise Dead - Pet) spell.
SPELL_ATTR7_UNK15 = 0x00008000, // 15 Exorcism. Usable on players? 100% crit chance on undead and demons?
- SPELL_ATTR7_UNK16 = 0x00010000, // 16 Druid spells (29166, 54833, 64372, 68285).
+ SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER = 0x00010000, // 16 These spells can replenish a powertype, which is not the current powertype.
SPELL_ATTR7_UNK17 = 0x00020000, // 17 Only 27965 (Suicide) spell.
SPELL_ATTR7_HAS_CHARGE_EFFECT = 0x00040000, // 18 Only spells that have Charge among effects.
SPELL_ATTR7_ZONE_TELEPORT = 0x00080000, // 19 Teleports to specific zones.
@@ -2594,7 +2595,7 @@ enum CreatureTypeFlags
CREATURE_TYPEFLAGS_EXOTIC = 0x00010000, // Can be tamed by hunter as exotic pet
CREATURE_TYPEFLAGS_UNK17 = 0x00020000, // ? Related to vehicles/pvp?
CREATURE_TYPEFLAGS_UNK18 = 0x00040000, // ? Related to vehicle/siege weapons?
- CREATURE_TYPEFLAGS_UNK19 = 0x00080000,
+ CREATURE_TYPEFLAGS_PROJECTILE_COLLISION = 0x00080000, // Projectiles can collide with this creature - interacts with TARGET_DEST_TRAJ
CREATURE_TYPEFLAGS_UNK20 = 0x00100000,
CREATURE_TYPEFLAGS_UNK21 = 0x00200000,
CREATURE_TYPEFLAGS_UNK22 = 0x00400000,
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index c181750a414..246d4682739 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -191,6 +191,10 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di
}
else
{
+ // Set home position at place on waypoint movement.
+ if (!creature->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) || !creature->GetTransGUID())
+ creature->SetHomePosition(creature->GetPosition());
+
if (creature->IsStopped())
Stop(STOP_TIME_FOR_PLAYER);
else if (creature->movespline->Finalized())
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 7365d592a62..f1359b70aa6 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -16,6 +16,7 @@
*/
#include "ScriptLoader.h"
+#include "World.h"
//examples
void AddSC_example_creature();
@@ -41,7 +42,7 @@ void AddSC_item_spell_scripts();
void AddSC_example_spell_scripts();
void AddSC_holiday_spell_scripts();
-void AddSC_SmartSCripts();
+void AddSC_SmartScripts();
//Commands
void AddSC_account_commandscript();
@@ -97,6 +98,7 @@ void AddSC_npc_innkeeper();
void AddSC_npcs_special();
void AddSC_npc_taxi();
void AddSC_achievement_scripts();
+void AddSC_action_ip_logger();
//eastern kingdoms
void AddSC_alterac_valley(); //Alterac Valley
@@ -469,7 +471,6 @@ void AddSC_boss_xt002();
void AddSC_boss_kologarn();
void AddSC_boss_assembly_of_iron();
void AddSC_boss_general_vezax();
-void AddSC_ulduar_teleporter();
void AddSC_boss_mimiron();
void AddSC_boss_hodir();
void AddSC_boss_freya();
@@ -696,6 +697,7 @@ void AddSC_outdoorpvp_zm();
// player
void AddSC_chat_log();
+void AddSC_action_ip_logger();
#endif
@@ -703,7 +705,7 @@ void AddScripts()
{
AddExampleScripts();
AddSpellScripts();
- AddSC_SmartSCripts();
+ AddSC_SmartScripts();
AddCommandScripts();
#ifdef SCRIPTS
AddWorldScripts();
@@ -804,7 +806,10 @@ void AddWorldScripts()
AddSC_npcs_special();
AddSC_npc_taxi();
AddSC_achievement_scripts();
- AddSC_chat_log();
+ AddSC_chat_log(); // location: scripts\World\chat_log.cpp
+ // To avoid duplicate code, we check once /*ONLY*/ if logging is permitted or not.
+ if (sWorld->getBoolConfig(CONFIG_IP_BASED_ACTION_LOGGING))
+ AddSC_action_ip_logger(); // location: scripts\World\action_ip_logger.cpp
#endif
}
@@ -1309,7 +1314,6 @@ void AddNorthrendScripts()
AddSC_boss_general_vezax();
AddSC_boss_assembly_of_iron();
AddSC_boss_kologarn();
- AddSC_ulduar_teleporter();
AddSC_boss_mimiron();
AddSC_boss_hodir();
AddSC_boss_freya();
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 94cf1047dfb..83f401d4e79 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -224,6 +224,7 @@ void ScriptMgr::Unload()
SCR_CLEAR(TransportScript);
SCR_CLEAR(AchievementCriteriaScript);
SCR_CLEAR(PlayerScript);
+ SCR_CLEAR(AccountScript);
SCR_CLEAR(GuildScript);
SCR_CLEAR(GroupScript);
SCR_CLEAR(UnitScript);
@@ -1242,9 +1243,9 @@ void ScriptMgr::OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck)
FOREACH_SCRIPT(PlayerScript)->OnSpellCast(player, spell, skipCheck);
}
-void ScriptMgr::OnPlayerLogin(Player* player)
+void ScriptMgr::OnPlayerLogin(Player* player, bool firstLogin)
{
- FOREACH_SCRIPT(PlayerScript)->OnLogin(player);
+ FOREACH_SCRIPT(PlayerScript)->OnLogin(player, firstLogin);
}
void ScriptMgr::OnPlayerLogout(Player* player)
@@ -1257,9 +1258,14 @@ void ScriptMgr::OnPlayerCreate(Player* player)
FOREACH_SCRIPT(PlayerScript)->OnCreate(player);
}
-void ScriptMgr::OnPlayerDelete(uint64 guid)
+void ScriptMgr::OnPlayerDelete(uint64 guid, uint32 accountId)
{
- FOREACH_SCRIPT(PlayerScript)->OnDelete(guid);
+ FOREACH_SCRIPT(PlayerScript)->OnDelete(guid, accountId);
+}
+
+void ScriptMgr::OnPlayerFailedDelete(uint64 guid, uint32 accountId)
+{
+ FOREACH_SCRIPT(PlayerScript)->OnFailedDelete(guid, accountId);
}
void ScriptMgr::OnPlayerSave(Player* player)
@@ -1277,6 +1283,37 @@ void ScriptMgr::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newAre
FOREACH_SCRIPT(PlayerScript)->OnUpdateZone(player, newZone, newArea);
}
+// Account
+void ScriptMgr::OnAccountLogin(uint32 accountId)
+{
+ FOREACH_SCRIPT(AccountScript)->OnAccountLogin(accountId);
+}
+
+void ScriptMgr::OnFailedAccountLogin(uint32 accountId)
+{
+ FOREACH_SCRIPT(AccountScript)->OnFailedAccountLogin(accountId);
+}
+
+void ScriptMgr::OnEmailChange(uint32 accountId)
+{
+ FOREACH_SCRIPT(AccountScript)->OnEmailChange(accountId);
+}
+
+void ScriptMgr::OnFailedEmailChange(uint32 accountId)
+{
+ FOREACH_SCRIPT(AccountScript)->OnFailedEmailChange(accountId);
+}
+
+void ScriptMgr::OnPasswordChange(uint32 accountId)
+{
+ FOREACH_SCRIPT(AccountScript)->OnPasswordChange(accountId);
+}
+
+void ScriptMgr::OnFailedPasswordChange(uint32 accountId)
+{
+ FOREACH_SCRIPT(AccountScript)->OnFailedPasswordChange(accountId);
+}
+
// Guild
void ScriptMgr::OnGuildAddMember(Guild* guild, Player* player, uint8& plRank)
{
@@ -1539,6 +1576,12 @@ PlayerScript::PlayerScript(const char* name)
ScriptRegistry<PlayerScript>::AddScript(this);
}
+AccountScript::AccountScript(const char* name)
+ : ScriptObject(name)
+{
+ ScriptRegistry<AccountScript>::AddScript(this);
+}
+
GuildScript::GuildScript(const char* name)
: ScriptObject(name)
{
@@ -1581,6 +1624,7 @@ template class ScriptRegistry<PlayerScript>;
template class ScriptRegistry<GuildScript>;
template class ScriptRegistry<GroupScript>;
template class ScriptRegistry<UnitScript>;
+template class ScriptRegistry<AccountScript>;
// Undefine utility macros.
#undef GET_SCRIPT_RET
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index bc84192eca9..ee95759c72e 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -29,6 +29,7 @@
#include "World.h"
#include "Weather.h"
+class AccountMgr;
class AuctionHouseObject;
class AuraScript;
class Battleground;
@@ -744,7 +745,7 @@ class PlayerScript : public UnitScript
virtual void OnSpellCast(Player* /*player*/, Spell* /*spell*/, bool /*skipCheck*/) { }
// Called when a player logs in.
- virtual void OnLogin(Player* /*player*/) { }
+ virtual void OnLogin(Player* /*player*/, bool /*firstLogin*/) { }
// Called when a player logs out.
virtual void OnLogout(Player* /*player*/) { }
@@ -753,7 +754,10 @@ class PlayerScript : public UnitScript
virtual void OnCreate(Player* /*player*/) { }
// Called when a player is deleted.
- virtual void OnDelete(uint64 /*guid*/) { }
+ virtual void OnDelete(uint64 /*guid*/, uint32 /*accountId*/) { }
+
+ // Called when a player delete failed
+ virtual void OnFailedDelete(uint64 /*guid*/, uint32 /*accountId*/) { }
// Called when a player is about to be saved.
virtual void OnSave(Player* /*player*/) { }
@@ -768,6 +772,33 @@ class PlayerScript : public UnitScript
virtual void OnMapChanged(Player* /*player*/) { }
};
+class AccountScript : public ScriptObject
+{
+ protected:
+
+ AccountScript(const char* name);
+
+ public:
+
+ // Called when an account logged in succesfully
+ virtual void OnAccountLogin(uint32 /*accountId*/) {}
+
+ // Called when an account login failed
+ virtual void OnFailedAccountLogin(uint32 /*accountId*/) {}
+
+ // Called when Email is successfully changed for Account
+ virtual void OnEmailChange(uint32 /*accountId*/) {}
+
+ // Called when Email failed to change for Account
+ virtual void OnFailedEmailChange(uint32 /*accountId*/) {}
+
+ // Called when Password is successfully changed for Account
+ virtual void OnPasswordChange(uint32 /*accountId*/) {}
+
+ // Called when Password failed to change for Account
+ virtual void OnFailedPasswordChange(uint32 /*accountId*/) {}
+};
+
class GuildScript : public ScriptObject
{
protected:
@@ -1034,14 +1065,24 @@ class ScriptMgr
void OnPlayerEmote(Player* player, uint32 emote);
void OnPlayerTextEmote(Player* player, uint32 textEmote, uint32 emoteNum, uint64 guid);
void OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck);
- void OnPlayerLogin(Player* player);
+ void OnPlayerLogin(Player* player, bool firstLogin);
void OnPlayerLogout(Player* player);
void OnPlayerCreate(Player* player);
- void OnPlayerDelete(uint64 guid);
+ void OnPlayerDelete(uint64 guid, uint32 accountId);
+ void OnPlayerFailedDelete(uint64 guid, uint32 accountId);
void OnPlayerSave(Player* player);
void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent);
void OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea);
+ public: /* AccountScript */
+
+ void OnAccountLogin(uint32 accountId);
+ void OnFailedAccountLogin(uint32 accountId);
+ void OnEmailChange(uint32 accountId);
+ void OnFailedEmailChange(uint32 accountId);
+ void OnPasswordChange(uint32 accountId);
+ void OnFailedPasswordChange(uint32 accountId);
+
public: /* GuildScript */
void OnGuildAddMember(Guild* guild, Player* player, uint8& plRank);
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 3ac31da3eb1..9f8b3785e92 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -1260,15 +1260,13 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
}
// Check if player is flooding some packets
- if (++packetCounter.amountCounter > maxPacketCounterAllowed)
- {
- TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)",
- Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(),
- opcodeTable[p.GetOpcode()].name, p.GetOpcode(), packetCounter.amountCounter);
- }
-
+ if (++packetCounter.amountCounter <= maxPacketCounterAllowed)
return true;
+ TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)",
+ Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(),
+ opcodeTable[p.GetOpcode()].name, p.GetOpcode(), packetCounter.amountCounter);
+
switch (_policy)
{
case POLICY_LOG:
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 61d2fa6d106..c8c81a415e1 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -444,7 +444,6 @@ class WorldSession
void HandleForceSpeedChangeAck(WorldPacket& recvData);
void HandlePingOpcode(WorldPacket& recvPacket);
- void HandleAuthSessionOpcode(WorldPacket& recvPacket);
void HandleRepopRequestOpcode(WorldPacket& recvPacket);
void HandleAutostoreLootItemOpcode(WorldPacket& recvPacket);
void HandleLootMoneyOpcode(WorldPacket& recvPacket);
@@ -979,10 +978,11 @@ class WorldSession
// characters who failed on Player::BuildEnumData shouldn't login
std::set<uint32> _legitCharacters;
- uint32 m_GUIDLow; // set loggined or recently logout player (while m_playerRecentlyLogout set)
+ uint32 m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set)
Player* _player;
WorldSocket* m_Socket;
- std::string m_Address;
+ std::string m_Address; // Current Remote Address
+ // std::string m_LAddress; // Last Attempted Remote Adress - we can not set attempted ip for a non-existing session!
AccountTypes _security;
uint32 _accountId;
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index 605b863bfa1..d35ee80099d 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -263,7 +263,7 @@ int WorldSocket::open (void *a)
return 0;
}
-int WorldSocket::close (u_long)
+int WorldSocket::close(u_long)
{
shutdown();
@@ -274,7 +274,7 @@ int WorldSocket::close (u_long)
return 0;
}
-int WorldSocket::handle_input (ACE_HANDLE)
+int WorldSocket::handle_input(ACE_HANDLE)
{
if (closing_)
return -1;
@@ -310,7 +310,7 @@ int WorldSocket::handle_input (ACE_HANDLE)
ACE_NOTREACHED(return -1);
}
-int WorldSocket::handle_output (ACE_HANDLE)
+int WorldSocket::handle_output(ACE_HANDLE)
{
ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1);
@@ -356,7 +356,7 @@ int WorldSocket::handle_output (ACE_HANDLE)
ACE_NOTREACHED (return 0);
}
-int WorldSocket::handle_output_queue (GuardType& g)
+int WorldSocket::handle_output_queue(GuardType& g)
{
if (msg_queue()->is_empty())
return cancel_wakeup_output(g);
@@ -417,7 +417,7 @@ int WorldSocket::handle_output_queue (GuardType& g)
ACE_NOTREACHED(return -1);
}
-int WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask)
+int WorldSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask)
{
// Critical section
{
@@ -617,7 +617,7 @@ int WorldSocket::handle_input_missing_data (void)
return size_t(n) == recv_size ? 1 : 2;
}
-int WorldSocket::cancel_wakeup_output (GuardType& g)
+int WorldSocket::cancel_wakeup_output(GuardType& g)
{
if (!m_OutActive)
return 0;
@@ -637,7 +637,7 @@ int WorldSocket::cancel_wakeup_output (GuardType& g)
return 0;
}
-int WorldSocket::schedule_wakeup_output (GuardType& g)
+int WorldSocket::schedule_wakeup_output(GuardType& g)
{
if (m_OutActive)
return 0;
@@ -758,6 +758,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
uint64 unk4;
WorldPacket packet, SendAddonPacked;
BigNumber k;
+ bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
if (sWorld->IsClosed())
{
@@ -795,6 +796,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
// Stop if the account is not found
if (!result)
{
+ // We can not log here, as we do not know the account. Thus, no accountId.
SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
return -1;
@@ -807,19 +809,34 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
if (expansion > world_expansion)
expansion = world_expansion;
+ // For hook purposes, we get Remoteaddress at this point.
+ std::string address = GetRemoteAddress();
+
+ // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
+
+ stmt->setString(0, address);
+ stmt->setString(1, account);
+
+ LoginDatabase.Execute(stmt);
+ // This also allows to check for possible "hack" attempts on account
+
+ // id has to be fetched at this point, so that first actual account response that fails can be logged
+ id = fields[0].GetUInt32();
+
///- Re-check ip locking (same check as in realmd).
if (fields[3].GetUInt8() == 1) // if ip is locked
{
- if (strcmp (fields[2].GetCString(), GetRemoteAddress().c_str()))
+ if (strcmp (fields[2].GetCString(), address.c_str()))
{
SendAuthResponseError(AUTH_FAILED);
- TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
+ TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str());
+ // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
+ sScriptMgr->OnFailedAccountLogin(id);
return -1;
}
}
- id = fields[0].GetUInt32();
-
k.SetHexStr(fields[1].GetCString());
int64 mutetime = fields[5].GetInt64();
@@ -844,10 +861,10 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
std::string os = fields[8].GetString();
// Must be done before WorldSession is created
- if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED) && os != "Win" && os != "OSX")
+ if (wardenActive && os != "Win" && os != "OSX")
{
SendAuthResponseError(AUTH_REJECT);
- TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", GetRemoteAddress().c_str(), os.c_str());
+ TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str());
return -1;
}
@@ -871,7 +888,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BANS);
stmt->setUInt32(0, id);
- stmt->setString(1, GetRemoteAddress());
+ stmt->setString(1, address);
PreparedQueryResult banresult = LoginDatabase.Query(stmt);
@@ -879,6 +896,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
{
SendAuthResponseError(AUTH_BANNED);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
+ sScriptMgr->OnFailedAccountLogin(id);
return -1;
}
@@ -889,6 +907,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
{
SendAuthResponseError(AUTH_UNAVAILABLE);
TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
+ sScriptMgr->OnFailedAccountLogin(id);
return -1;
}
@@ -903,8 +922,6 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
sha.UpdateBigNumbers(&k, NULL);
sha.Finalize();
- std::string address = GetRemoteAddress();
-
if (memcmp(sha.GetDigest(), digest, 20))
{
SendAuthResponseError(AUTH_FAILED);
@@ -927,8 +944,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
if (result)
isRecruiter = true;
- // Update the last_ip in the database
-
+ // Update the last_ip in the database as it was successful for login
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
stmt->setString(0, address);
@@ -946,8 +962,11 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
m_Session->ReadAddonsInfo(recvPacket);
m_Session->LoadPermissions();
+ // At this point, we can safely hook a successful login
+ sScriptMgr->OnAccountLogin(id);
+
// Initialize Warden system only if it is enabled by config
- if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED))
+ if (wardenActive)
m_Session->InitWarden(&k, os);
// Sleep this Network thread for
@@ -958,7 +977,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
return 0;
}
-int WorldSocket::HandlePing (WorldPacket& recvPacket)
+int WorldSocket::HandlePing(WorldPacket& recvPacket)
{
uint32 ping;
uint32 latency;
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index a0883c895d3..152dc903825 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -379,8 +379,9 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster):
m_base(base), m_spellInfo(base->GetSpellInfo()),
m_baseAmount(baseAmount ? *baseAmount : m_spellInfo->Effects[effIndex].BasePoints),
+m_damage(0), m_critChance(0.0f), m_donePct(1.0f),
m_spellmod(NULL), m_periodicTimer(0), m_tickNumber(0), m_effIndex(effIndex),
-m_canBeRecalculated(true), m_damage(0), m_critChance(0.0f), m_donePct(1.0f), m_isPeriodic(false)
+m_canBeRecalculated(true), m_isPeriodic(false)
{
CalculatePeriodic(caster, true, false);
@@ -3493,11 +3494,23 @@ void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8
return;
Unit* target = aurApp->GetTarget();
+ int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_RESISTANCE_PCT);
+ if (abs(spellGroupVal) >= abs(GetAmount()))
+ return;
for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
{
if (GetMiscValue() & int32(1<<i))
{
+ if (spellGroupVal)
+ {
+ target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, (float)spellGroupVal, !apply);
+ if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet())
+ {
+ target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)spellGroupVal, !apply);
+ target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)spellGroupVal, !apply);
+ }
+ }
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetAmount()), apply);
if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet())
{
@@ -3557,19 +3570,29 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
- Unit* target = aurApp->GetTarget();
-
if (GetMiscValue() < -2 || GetMiscValue() > 4)
{
TC_LOG_ERROR("spells", "WARNING: Spell %u effect %u has an unsupported misc value (%i) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue());
return;
}
+ Unit* target = aurApp->GetTarget();
+ int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true, GetMiscValue());
+ if (abs(spellGroupVal) >= abs(GetAmount()))
+ return;
+
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
// -1 or -2 is all stats (misc < -2 checked in function beginning)
if (GetMiscValue() < 0 || GetMiscValue() == i)
{
+ if (spellGroupVal)
+ {
+ target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(spellGroupVal), !apply);
+ if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet())
+ target->ApplyStatBuffMod(Stats(i), float(spellGroupVal), !apply);
+ }
+
//target->ApplyStatMod(Stats(i), m_amount, apply);
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply);
if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet())
@@ -3681,14 +3704,30 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
- Unit* target = aurApp->GetTarget();
-
if (GetMiscValue() < -1 || GetMiscValue() > 4)
{
TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid");
return;
}
+ Unit* target = aurApp->GetTarget();
+ int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, -1);
+ if (abs(spellGroupVal) >= abs(GetAmount()))
+ return;
+
+ if (spellGroupVal)
+ {
+ for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
+ {
+ if (GetMiscValue() == i || GetMiscValue() == -1) // affect the same stats
+ {
+ target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal), !apply);
+ if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet())
+ target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal), !apply);
+ }
+ }
+ }
+
// save current health state
float healthPct = target->GetHealthPct();
bool alive = target->IsAlive();
@@ -3697,6 +3736,17 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8
{
if (GetMiscValue() == i || GetMiscValue() == -1)
{
+ int32 spellGroupVal2 = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, i);
+ if (abs(spellGroupVal2) >= abs(GetAmount()))
+ continue;
+
+ if (spellGroupVal2)
+ {
+ target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal2), !apply);
+ if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet())
+ target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal2), !apply);
+ }
+
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetAmount()), apply);
if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet())
target->ApplyStatPercentBuffMod(Stats(i), float(GetAmount()), apply);
@@ -4095,7 +4145,17 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo
return;
Unit* target = aurApp->GetTarget();
+ int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MELEE_SLOW);
+ if (abs(spellGroupVal) >= abs(GetAmount()))
+ return;
+ if (spellGroupVal)
+ {
+ target->ApplyCastTimePercentMod(float(spellGroupVal), !apply);
+ target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
+ target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
+ target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply);
+ }
target->ApplyCastTimePercentMod(float(m_amount), apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply);
@@ -4119,7 +4179,15 @@ void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mod
return;
Unit* target = aurApp->GetTarget();
+ int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_MELEE_HASTE);
+ if (abs(spellGroupVal) >= abs(GetAmount()))
+ return;
+ if (spellGroupVal)
+ {
+ target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
+ target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
+ }
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply);
}
@@ -4356,7 +4424,8 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8
return;
Unit* target = aurApp->GetTarget();
- if (!target)
+ int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
+ if (abs(spellGroupVal) >= abs(GetAmount()))
return;
if (target->GetTypeId() == TYPEID_PLAYER)
@@ -4368,12 +4437,23 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) && (GetSpellInfo()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER))
{
+ if (spellGroupVal)
+ {
+ target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(spellGroupVal), !apply);
+ target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(spellGroupVal), !apply);
+ target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(spellGroupVal), !apply);
+ }
target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetAmount()), apply);
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float (GetAmount()), apply);
+ if (Player* player = target->ToPlayer())
+ {
+ if (spellGroupVal)
+ player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(spellGroupVal), !apply);
+
+ player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(GetAmount()), apply);
+ }
}
else
{
@@ -4520,28 +4600,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
// AT APPLY
if (apply)
{
- // Overpower
- if (caster && m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR &&
- m_spellInfo->SpellFamilyFlags[0] & 0x4)
- {
- // In addition, if you strike a player..
- if (target->GetTypeId() != TYPEID_PLAYER)
- return;
- // ..while they are casting
- if (target->IsNonMeleeSpellCast(false, false, true, false, true))
- if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARRIOR, 2775, 0))
- switch (aurEff->GetId())
- {
- // Unrelenting Assault, rank 1
- case 46859:
- target->CastSpell(target, 64849, true, NULL, aurEff);
- break;
- // Unrelenting Assault, rank 2
- case 46860:
- target->CastSpell(target, 64850, true, NULL, aurEff);
- break;
- }
- }
switch (GetId())
{
case 1515: // Tame beast
@@ -6242,6 +6300,9 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons
{
Powers powerType = Powers(GetMiscValue());
+ if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() != powerType && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
+ return;
+
if (!target->IsAlive() || !target->GetMaxPower(powerType))
return;
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 683059b8e99..75dbd457b91 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -539,6 +539,9 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
|| !CanBeAppliedOn(itr->first))
addUnit = false;
+ if (addUnit && !itr->first->IsHighestExclusiveAura(this, true))
+ addUnit = false;
+
if (addUnit)
{
// persistent area aura does not hit flying targets
@@ -691,21 +694,12 @@ void Aura::Update(uint32 diff, Unit* caster)
if (int32(caster->GetHealth()) > manaPerSecond)
caster->ModifyHealth(-manaPerSecond);
else
- {
Remove();
- return;
- }
}
+ else if (int32(caster->GetPower(powertype)) >= manaPerSecond)
+ caster->ModifyPower(powertype, -manaPerSecond);
else
- {
- if (int32(caster->GetPower(powertype)) >= manaPerSecond)
- caster->ModifyPower(powertype, -manaPerSecond);
- else
- {
- Remove();
- return;
- }
- }
+ Remove();
}
}
}
@@ -731,17 +725,17 @@ int32 Aura::CalcMaxDuration(Unit* caster) const
// IsPermanent() checks max duration (which we are supposed to calculate here)
if (maxDuration != -1 && modOwner)
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, maxDuration);
+
return maxDuration;
}
void Aura::SetDuration(int32 duration, bool withMods)
{
if (withMods)
- {
if (Unit* caster = GetCaster())
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration);
- }
+
m_duration = duration;
SetNeedClientUpdateForTargets();
}
@@ -779,6 +773,7 @@ void Aura::SetCharges(uint8 charges)
{
if (m_procCharges == charges)
return;
+
m_procCharges = charges;
m_isUsingCharges = m_procCharges != 0;
SetNeedClientUpdateForTargets();
@@ -793,6 +788,7 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const
if (caster)
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, maxProcCharges);
+
return maxProcCharges;
}
@@ -815,6 +811,7 @@ bool Aura::ModCharges(int32 num, AuraRemoveMode removeMode)
SetCharges(charges);
}
+
return false;
}
@@ -883,6 +880,7 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode)
if (SpellModifier* mod = aurEff->GetSpellModifier())
mod->charges = GetCharges();
}
+
SetNeedClientUpdateForTargets();
return false;
}
@@ -894,13 +892,22 @@ void Aura::RefreshSpellMods()
player->RestoreAllSpellMods(0, this);
}
+bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const
+{
+ uint32 count = 0;
+ for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (HasEffect(i) && AuraType(GetSpellInfo()->Effects[i].ApplyAuraName) == auraType)
+ ++count;
+
+ return count > 1;
+}
+
bool Aura::IsArea() const
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
if (HasEffect(i) && GetSpellInfo()->Effects[i].IsAreaAuraEffect())
return true;
- }
+
return false;
}
@@ -1699,7 +1706,7 @@ void Aura::HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* cast
break;
}
default:
- break;
+ break;
}
}
}
@@ -1758,13 +1765,19 @@ bool Aura::CanStackWith(Aura const* existingAura) const
return false;
// check spell group stack rules
- SpellGroupStackRule stackRule = sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo);
- if (stackRule)
+ switch (sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo))
{
- if (stackRule == SPELL_GROUP_STACK_RULE_EXCLUSIVE)
- return false;
- if (sameCaster && stackRule == SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER)
+ case SPELL_GROUP_STACK_RULE_EXCLUSIVE:
+ case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST: // if it reaches this point, existing aura is lower/equal
return false;
+ case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER:
+ if (sameCaster)
+ return false;
+ break;
+ case SPELL_GROUP_STACK_RULE_DEFAULT:
+ case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT:
+ default:
+ break;
}
if (m_spellInfo->SpellFamilyName != existingSpellInfo->SpellFamilyName)
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index 669d2a529a1..8c426ea2175 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -149,6 +149,7 @@ class Aura
uint8 GetCasterLevel() const { return m_casterLevel; }
+ bool HasMoreThanOneEffectForType(AuraType auraType) const;
bool IsArea() const;
bool IsPassive() const;
bool IsDeathPersistent() const;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index ca170187e82..9086a304e1c 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1514,10 +1514,24 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex)
std::list<WorldObject*>::const_iterator itr = targets.begin();
for (; itr != targets.end(); ++itr)
{
+ if (!m_caster->HasInLine(*itr, 5.0f))
+ continue;
+
+ if (m_spellInfo->CheckTarget(m_caster, *itr, true) != SPELL_CAST_OK)
+ continue;
+
if (Unit* unitTarget = (*itr)->ToUnit())
- if (m_caster == *itr || m_caster->IsOnVehicle(unitTarget) || (unitTarget)->GetVehicle())//(*itr)->IsOnVehicle(m_caster))
+ {
+ if (m_caster == *itr || m_caster->IsOnVehicle(unitTarget) || unitTarget->GetVehicle())
continue;
+ if (Creature* creatureTarget = unitTarget->ToCreature())
+ {
+ if (!(creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_PROJECTILE_COLLISION))
+ continue;
+ }
+ }
+
const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3)
/// @todo all calculation should be based on src instead of m_caster
const float objDist2d = m_targets.GetSrcPos()->GetExactDist2d(*itr) * std::cos(m_targets.GetSrcPos()->GetRelativeAngle(*itr));
@@ -2607,10 +2621,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
// Haste modifies duration of channeled spells
if (m_spellInfo->IsChanneled())
- {
- if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
- m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this);
- }
+ m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this);
// and duration of auras affected by SPELL_AURA_PERIODIC_HASTE
else if (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, aurSpellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
duration = int32(duration * m_originalCaster->GetFloatValue(UNIT_MOD_CAST_SPEED));
@@ -3234,9 +3245,9 @@ void Spell::handle_immediate()
// Apply duration mod
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
+
// Apply haste mods
- if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
- m_caster->ModSpellCastTime(m_spellInfo, duration, this);
+ m_caster->ModSpellCastTime(m_spellInfo, duration, this);
m_spellState = SPELL_STATE_CASTING;
m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags);
@@ -3765,7 +3776,7 @@ void Spell::SendSpellStart()
castFlags |= CAST_FLAG_POWER_LEFT_SELF;
if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNE)
- castFlags |= CAST_FLAG_UNKNOWN_19;
+ castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2));
if (m_CastItem)
@@ -3821,21 +3832,22 @@ void Spell::SendSpellGo()
if ((m_caster->GetTypeId() == TYPEID_PLAYER)
&& (m_caster->getClass() == CLASS_DEATH_KNIGHT)
&& m_spellInfo->RuneCostID
- && m_spellInfo->PowerType == POWER_RUNE)
+ && m_spellInfo->PowerType == POWER_RUNE
+ && !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST))
{
- castFlags |= CAST_FLAG_UNKNOWN_19; // same as in SMSG_SPELL_START
+ castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list
}
if (m_spellInfo->HasEffect(SPELL_EFFECT_ACTIVATE_RUNE))
- {
castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list
- castFlags |= CAST_FLAG_UNKNOWN_19; // same as in SMSG_SPELL_START
- }
if (m_targets.HasTraj())
castFlags |= CAST_FLAG_ADJUST_MISSILE;
+ if (!m_spellInfo->StartRecoveryTime)
+ castFlags |= CAST_FLAG_NO_GCD;
+
WorldPacket data(SMSG_SPELL_GO, 50); // guess size
if (m_CastItem)
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 341867ff787..584c20fdfb3 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -57,7 +57,7 @@ enum SpellCastFlags
CAST_FLAG_UNKNOWN_16 = 0x00008000,
CAST_FLAG_UNKNOWN_17 = 0x00010000,
CAST_FLAG_ADJUST_MISSILE = 0x00020000,
- CAST_FLAG_UNKNOWN_19 = 0x00040000,
+ CAST_FLAG_NO_GCD = 0x00040000, // no GCD for spell casts from charm/summon (vehicle spells is an example)
CAST_FLAG_VISUAL_CHAIN = 0x00080000,
CAST_FLAG_UNKNOWN_21 = 0x00100000,
CAST_FLAG_RUNE_LIST = 0x00200000,
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 48c73cf39ca..606851bf8f1 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -836,10 +836,10 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
{
// remove all harmful spells on you...
SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
- if ((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC // only affect magic spells
- || ((spell->GetDispelMask()) & dispelMask))
+ if (((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && spell->GetSchoolMask() != SPELL_SCHOOL_MASK_NORMAL) // only affect magic spells
+ || (spell->GetDispelMask() & dispelMask)) &&
// ignore positive and passive auras
- && !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive())
+ !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive())
{
m_caster->RemoveAura(iter);
}
@@ -1751,6 +1751,12 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
+ return;
+
+ if (unitTarget->GetMaxPower(power) == 0)
+ return;
+
// Some level depends spells
int level_multiplier = 0;
int level_diff = 0;
@@ -1796,9 +1802,6 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
if (damage < 0)
return;
- if (unitTarget->GetMaxPower(power) == 0)
- return;
-
m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power);
// Mad Alchemist's Potion
@@ -1863,6 +1866,9 @@ void Spell::EffectEnergizePct(SpellEffIndex effIndex)
Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
+ return;
+
uint32 maxPower = unitTarget->GetMaxPower(power);
if (maxPower == 0)
return;
@@ -2602,8 +2608,16 @@ void Spell::EffectLearnSkill(SpellEffIndex effIndex)
return;
uint32 skillid = m_spellInfo->Effects[effIndex].MiscValue;
+ SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skillid, unitTarget->getRace(), unitTarget->getClass());
+ if (!rcEntry)
+ return;
+
+ SkillTiersEntry const* tier = sSkillTiersStore.LookupEntry(rcEntry->SkillTier);
+ if (!tier)
+ return;
+
uint16 skillval = unitTarget->ToPlayer()->GetPureSkillValue(skillid);
- unitTarget->ToPlayer()->SetSkill(skillid, m_spellInfo->Effects[effIndex].CalcValue(), skillval?skillval:1, damage*75);
+ unitTarget->ToPlayer()->SetSkill(skillid, m_spellInfo->Effects[effIndex].CalcValue(), std::max<uint16>(skillval, 1), tier->MaxSkill[damage - 1]);
}
void Spell::EffectAddHonor(SpellEffIndex /*effIndex*/)
@@ -4049,51 +4063,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
}
break;
}
- case SPELLFAMILY_DEATHKNIGHT:
- {
- // Pestilence
- if (m_spellInfo->SpellFamilyFlags[1]&0x10000)
- {
- // Get diseases on target of spell
- if (m_targets.GetUnitTarget() && // Glyph of Disease - cast on unit target too to refresh aura
- (m_targets.GetUnitTarget() != unitTarget || m_caster->HasAura(63334)))
- {
- // And spread them on target
- // Blood Plague
- if (m_targets.GetUnitTarget()->HasAura(55078))
- {
- AuraEffect* aurEffOld = m_targets.GetUnitTarget()->GetAura(55078)->GetEffect(0);
- float donePct = aurEffOld->GetDonePct();
- float critChance = aurEffOld->GetCritChance();
-
- m_caster->CastSpell(unitTarget, 55078, true);
-
- if (unitTarget->HasAura(55078))
- if (AuraEffect* aurEffNew = unitTarget->GetAura(55078)->GetEffect(0))
- {
- aurEffNew->SetCritChance(critChance); // Blood Plague can crit if caster has T9.
- aurEffNew->SetDonePct(donePct);
- aurEffNew->SetDamage(m_caster->SpellDamageBonusDone(unitTarget, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct);
- }
- }
- // Frost Fever
- if (m_targets.GetUnitTarget()->HasAura(55095))
- {
- float donePct = m_targets.GetUnitTarget()->GetAura(55095)->GetEffect(0)->GetDonePct();
-
- m_caster->CastSpell(unitTarget, 55095, true);
-
- if (unitTarget->HasAura(55095))
- if (AuraEffect* aurEffNew = unitTarget->GetAura(55095)->GetEffect(0))
- {
- aurEffNew->SetDonePct(donePct);
- aurEffNew->SetDamage(m_caster->SpellDamageBonusDone(unitTarget, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct);
- }
- }
- }
- }
- break;
- }
}
// normal DB scripted effect
@@ -4743,6 +4712,7 @@ void Spell::EffectSkinning(SpellEffIndex /*effIndex*/)
m_caster->ToPlayer()->SendLoot(creature->GetGUID(), LOOT_SKINNING);
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
+ creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index ba4c3deca85..4d97dc97e5b 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1207,10 +1207,8 @@ bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
return true;
- // these spells (Cyclone for example) can pierce all...
- if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)
- // ...but not these (Divine shield for example)
- && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY)))
+ // these spells (Cyclone for example) can pierce all... // ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
+ if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH)))
return true;
return false;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 75243139fec..e954b9173ad 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -765,6 +765,15 @@ SpellGroupStackRule SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellIn
return rule;
}
+SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const
+{
+ SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group);
+ if (itr != mSpellGroupStack.end())
+ return itr->second;
+
+ return SPELL_GROUP_STACK_RULE_DEFAULT;
+}
+
SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
{
SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId);
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 7b54aca3759..757bd813613 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -349,14 +349,14 @@ typedef std::pair<SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_
enum SpellGroupStackRule
{
- SPELL_GROUP_STACK_RULE_DEFAULT = 0,
- SPELL_GROUP_STACK_RULE_EXCLUSIVE = 1,
- SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER = 2,
- SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT = 3
+ SPELL_GROUP_STACK_RULE_DEFAULT,
+ SPELL_GROUP_STACK_RULE_EXCLUSIVE,
+ SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER,
+ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT,
+ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST,
+ SPELL_GROUP_STACK_RULE_MAX
};
-#define SPELL_GROUP_STACK_RULE_MAX 4
-
typedef std::map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap;
struct SpellThreatEntry
@@ -655,6 +655,7 @@ class SpellMgr
// Spell Group Stack Rules table
bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, int32 amount, std::map<SpellGroup, int32>& groups) const;
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const;
+ SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const;
// Spell proc event table
SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index e40e2f7e6d1..78470d4e790 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1044,6 +1044,8 @@ void World::LoadConfigSettings(bool reload)
m_bool_configs[CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN] = sConfigMgr->GetBoolDefault("OffhandCheckAtSpellUnlearn", true);
+ m_int_configs[CONFIG_CREATURE_PICKPOCKET_REFILL] = sConfigMgr->GetIntDefault("Creature.PickPocketRefillDelay", 10 * MINUTE);
+
if (int32 clientCacheId = sConfigMgr->GetIntDefault("ClientCacheVersion", 0))
{
// overwrite DB/old value
@@ -1253,6 +1255,10 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_BIRTHDAY_TIME] = sConfigMgr->GetIntDefault("BirthdayTime", 1222964635);
+ m_bool_configs[CONFIG_IP_BASED_ACTION_LOGGING] = sConfigMgr->GetBoolDefault("Allow.IP.Based.Action.Logging", false);
+
+ m_bool_configs[CONFIG_IP_BASED_LOGIN_LOGGING] = sConfigMgr->GetBoolDefault("Wrong.Password.Login.Logging", false);
+
// call ScriptMgr if we're reloading the configuration
if (reload)
sScriptMgr->OnConfigLoad(reload);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 9bac3032161..61acdc37b07 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -154,6 +154,8 @@ enum WorldBoolConfigs
CONFIG_EVENT_ANNOUNCE,
CONFIG_STATS_LIMITS_ENABLE,
CONFIG_INSTANCES_RESET_ANNOUNCE,
+ CONFIG_IP_BASED_ACTION_LOGGING,
+ CONFIG_IP_BASED_LOGIN_LOGGING,
BOOL_CONFIG_VALUE_COUNT
};
@@ -331,6 +333,7 @@ enum WorldIntConfigs
CONFIG_BG_REWARD_LOSER_HONOR_FIRST,
CONFIG_BG_REWARD_LOSER_HONOR_LAST,
CONFIG_BIRTHDAY_TIME,
+ CONFIG_CREATURE_PICKPOCKET_REFILL,
INT_CONFIG_VALUE_COUNT
};
diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt
index c1a9435de52..938520209a0 100644
--- a/src/server/scripts/CMakeLists.txt
+++ b/src/server/scripts/CMakeLists.txt
@@ -47,7 +47,9 @@ message("")
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/zlib
diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp
index 3c9714ca55a..1121e4d0a2f 100644
--- a/src/server/scripts/Commands/cs_account.cpp
+++ b/src/server/scripts/Commands/cs_account.cpp
@@ -377,6 +377,7 @@ public:
if (!AccountMgr::CheckEmail(handler->GetSession()->GetAccountId(), std::string(oldEmail)))
{
handler->SendSysMessage(LANG_COMMAND_WRONGEMAIL);
+ sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
handler->SetSentErrorMessage(true);
TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change email, but the provided email [%s] is not equal to registration email [%s].",
handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
@@ -388,6 +389,7 @@ public:
if (!AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), std::string(password)))
{
handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD);
+ sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
handler->SetSentErrorMessage(true);
TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change email, but the provided password is wrong.",
handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
@@ -398,6 +400,7 @@ public:
if (strcmp(email, oldEmail) == 0)
{
handler->SendSysMessage(LANG_OLD_EMAIL_IS_NEW_EMAIL);
+ sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
handler->SetSentErrorMessage(true);
return false;
}
@@ -405,6 +408,7 @@ public:
if (strcmp(email, emailConfirmation) != 0)
{
handler->SendSysMessage(LANG_NEW_EMAILS_NOT_MATCH);
+ sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
handler->SetSentErrorMessage(true);
TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change email, but the provided password is wrong.",
handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
@@ -418,6 +422,7 @@ public:
{
case AOR_OK:
handler->SendSysMessage(LANG_COMMAND_EMAIL);
+ sScriptMgr->OnEmailChange(handler->GetSession()->GetAccountId());
TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Email from [%s] to [%s].",
handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(),
@@ -425,6 +430,7 @@ public:
break;
case AOR_EMAIL_TOO_LONG:
handler->SendSysMessage(LANG_EMAIL_TOO_LONG);
+ sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
handler->SetSentErrorMessage(true);
return false;
default:
@@ -469,6 +475,7 @@ public:
if (!AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), std::string(oldPassword)))
{
handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD);
+ sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId());
handler->SetSentErrorMessage(true);
TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password, but the provided old password is wrong.",
handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
@@ -481,6 +488,7 @@ public:
&& !AccountMgr::CheckEmail(handler->GetSession()->GetAccountId(), std::string(emailConfirmation))) // ... and returns false if the comparison fails.
{
handler->SendSysMessage(LANG_COMMAND_WRONGEMAIL);
+ sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId());
handler->SetSentErrorMessage(true);
TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password, but the entered email [%s] is wrong.",
handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
@@ -493,6 +501,7 @@ public:
if (strcmp(newPassword, passwordConfirmation) != 0)
{
handler->SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH);
+ sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId());
handler->SetSentErrorMessage(true);
return false;
}
@@ -503,12 +512,14 @@ public:
{
case AOR_OK:
handler->SendSysMessage(LANG_COMMAND_PASSWORD);
+ sScriptMgr->OnPasswordChange(handler->GetSession()->GetAccountId());
TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Password.",
handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow());
break;
case AOR_PASS_TOO_LONG:
handler->SendSysMessage(LANG_PASSWORD_TOO_LONG);
+ sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId());
handler->SetSentErrorMessage(true);
return false;
default:
diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp
index 3c1fa973cd8..44ebb1ea4e0 100644
--- a/src/server/scripts/Commands/cs_go.cpp
+++ b/src/server/scripts/Commands/cs_go.cpp
@@ -29,6 +29,7 @@ EndScriptData */
#include "Chat.h"
#include "Language.h"
#include "Player.h"
+#include "Transport.h"
class go_commandscript : public CommandScript
{
@@ -132,21 +133,24 @@ public:
float x = fields[0].GetFloat();
float y = fields[1].GetFloat();
float z = fields[2].GetFloat();
- float ort = fields[3].GetFloat();
- int mapId = fields[4].GetUInt16();
+ float o = fields[3].GetFloat();
+ uint32 mapId = fields[4].GetUInt16();
uint32 guid = fields[5].GetUInt32();
uint32 id = fields[6].GetUInt32();
- // if creature is in same map with caster go at its current location
- if (Creature* creature = sObjectAccessor->GetCreature(*player, MAKE_NEW_GUID(guid, id, HIGHGUID_UNIT)))
+ Transport* transport = NULL;
+
+ if (Creature* creature = ObjectAccessor::GetObjectInWorld(MAKE_NEW_GUID(guid, id, HIGHGUID_UNIT), (Creature*)NULL))
{
x = creature->GetPositionX();
y = creature->GetPositionY();
z = creature->GetPositionZ();
- ort = creature->GetOrientation();
+ o = creature->GetOrientation();
+ mapId = creature->GetMapId();
+ transport = creature->GetTransport();
}
- if (!MapManager::IsValidMapCoord(mapId, x, y, z, ort))
+ if (!MapManager::IsValidMapCoord(mapId, x, y, z, o) || sObjectMgr->IsTransportMap(mapId))
{
handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapId);
handler->SetSentErrorMessage(true);
@@ -163,7 +167,11 @@ public:
else
player->SaveRecallPosition();
- player->TeleportTo(mapId, x, y, z, ort);
+ if (player->TeleportTo(mapId, x, y, z, o))
+ {
+ if (transport)
+ transport->AddPassenger(player);
+ }
return true;
}
@@ -274,8 +282,8 @@ public:
if (!guid)
return false;
- float x, y, z, ort;
- int mapId;
+ float x, y, z, o;
+ uint32 mapId;
// by DB guid
if (GameObjectData const* goData = sObjectMgr->GetGOData(guid))
@@ -283,7 +291,7 @@ public:
x = goData->posX;
y = goData->posY;
z = goData->posZ;
- ort = goData->orientation;
+ o = goData->orientation;
mapId = goData->mapid;
}
else
@@ -293,7 +301,7 @@ public:
return false;
}
- if (!MapManager::IsValidMapCoord(mapId, x, y, z, ort))
+ if (!MapManager::IsValidMapCoord(mapId, x, y, z, o) || sObjectMgr->IsTransportMap(mapId))
{
handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapId);
handler->SetSentErrorMessage(true);
@@ -310,7 +318,7 @@ public:
else
player->SaveRecallPosition();
- player->TeleportTo(mapId, x, y, z, ort);
+ player->TeleportTo(mapId, x, y, z, o);
return true;
}
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 28d49fe11aa..9cf8c041883 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -43,6 +43,7 @@ struct EnumName
#define CREATE_NAMED_ENUM(VALUE) { VALUE, STRINGIZE(VALUE) }
#define NPCFLAG_COUNT 24
+#define FLAGS_EXTRA_COUNT 16
EnumName<NPCFlags, int32> const npcFlagTexts[NPCFLAG_COUNT] =
{
@@ -144,6 +145,26 @@ EnumName<UnitFlags> const unitFlags[MAX_UNIT_FLAGS] =
CREATE_NAMED_ENUM(UNIT_FLAG_UNK_31)
};
+EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] =
+{
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_INSTANCE_BIND),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_CIVILIAN),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_BLOCK),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRUSH),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_XP_AT_KILL),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TRIGGER),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_TAUNT),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_WORLDEVENT),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_GUARD),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRIT),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_SKILLGAIN),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TAUNT_DIMINISH),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_ALL_DIMINISH),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS)
+};
+
class npc_commandscript : public CommandScript
{
public:
@@ -730,6 +751,10 @@ public:
handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor());
handler->PSendSysMessage(LANG_NPCINFO_POSITION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str());
+ handler->PSendSysMessage(LANG_NPCINFO_FLAGS_EXTRA, cInfo->flags_extra);
+ for (uint8 i = 0; i < FLAGS_EXTRA_COUNT; ++i)
+ if (cInfo->flags_extra & flagsExtra[i].Value)
+ handler->PSendSysMessage("%s (0x%X)", flagsExtra[i].Name, flagsExtra[i].Value);
for (uint8 i = 0; i < NPCFLAG_COUNT; i++)
if (npcflags & npcFlagTexts[i].Value)
diff --git a/src/server/scripts/Custom/CMakeLists.txt b/src/server/scripts/Custom/CMakeLists.txt
index 78db719ae6e..80ebe36b555 100644
--- a/src/server/scripts/Custom/CMakeLists.txt
+++ b/src/server/scripts/Custom/CMakeLists.txt
@@ -8,8 +8,11 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# file(GLOB_RECURSE sources_Custom Custom/*.cpp Custom/*.h)
+
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
+# ${sources_Custom}
)
message(" -> Prepared: Custom")
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp
index 2a473754ce6..f9757997731 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp
@@ -144,7 +144,7 @@ class npc_core_rager : public CreatureScript
if (HealthAbovePct(50) || !instance)
return;
- if (Creature* pGolemagg = instance->instance->GetCreature(instance->GetData64(BOSS_GOLEMAGG_THE_INCINERATOR)))
+ if (Creature* pGolemagg = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_GOLEMAGG_THE_INCINERATOR)))
{
if (pGolemagg->IsAlive())
{
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
index 3c4b372808b..7944011c7a0 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
@@ -150,14 +150,14 @@ public:
Phase = 0;
- instance->SetData(DATA_KAELTHAS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_KAELTHAS, NOT_STARTED);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
- instance->SetData(DATA_KAELTHAS_EVENT, DONE);
+ instance->SetBossState(DATA_KAELTHAS, DONE);
// Enable the Translocation Orb Exit
if (GameObject* escapeOrb = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_ESCAPE_ORB)))
@@ -172,7 +172,7 @@ public:
void EnterCombat(Unit* /*who*/) override
{
- instance->SetData(DATA_KAELTHAS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_KAELTHAS, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* who) override
@@ -515,7 +515,7 @@ public:
return;
}
//Don't really die in all phases of Kael'Thas
- if (instance->GetData(DATA_KAELTHAS_EVENT) == 0)
+ if (instance->GetBossState(DATA_KAELTHAS) == 0)
{
//prevent death
damage = 0;
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp
index 8dc8ff799ba..2af9d9b1567 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp
@@ -153,7 +153,7 @@ public:
//this mean she at some point evaded
void JustReachedHome() override
{
- instance->SetData(DATA_DELRISSA_EVENT, FAIL);
+ instance->SetBossState(DATA_DELRISSA, FAIL);
}
void EnterCombat(Unit* who) override
@@ -172,7 +172,7 @@ public:
}
}
- instance->SetData(DATA_DELRISSA_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_DELRISSA, IN_PROGRESS);
}
void InitializeLackeys()
@@ -240,7 +240,7 @@ public:
Talk(SAY_DEATH);
if (instance->GetData(DATA_DELRISSA_DEATH_COUNT) == MAX_ACTIVE_LACKEY)
- instance->SetData(DATA_DELRISSA_EVENT, DONE);
+ instance->SetBossState(DATA_DELRISSA, DONE);
else
{
if (me->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE))
@@ -434,7 +434,7 @@ struct boss_priestess_lackey_commonAI : public ScriptedAI
if (!pDelrissa->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE))
pDelrissa->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
- instance->SetData(DATA_DELRISSA_EVENT, DONE);
+ instance->SetBossState(DATA_DELRISSA, DONE);
}
}
}
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp
index d77f5db9cea..d6c0f95f967 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp
@@ -119,7 +119,7 @@ public:
}
// Set Inst data for encounter
- instance->SetData(DATA_SELIN_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_SELIN, NOT_STARTED);
DrainLifeTimer = urand(3000, 7000);
DrainManaTimer = DrainLifeTimer + 5000;
@@ -194,7 +194,7 @@ public:
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
- instance->SetData(DATA_SELIN_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_SELIN, IN_PROGRESS);
}
void KilledUnit(Unit* /*victim*/) override
@@ -228,7 +228,7 @@ public:
{
Talk(SAY_DEATH);
- instance->SetData(DATA_SELIN_EVENT, DONE); // Encounter complete!
+ instance->SetBossState(DATA_SELIN, DONE); // Encounter complete!
ShatterRemainingCrystals();
}
@@ -351,7 +351,7 @@ public:
}
}
}
- } else TC_LOG_ERROR("scripts", ERROR_INST_DATA);
+ }
}
};
};
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp
index 58b9ef12095..b9930820303 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -16,13 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Boss_Vexallus
-SD%Complete: 90
-SDComment: Heroic and Normal support. Needs further testing.
-SDCategory: Magister's Terrace
-EndScriptData */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "magisters_terrace.h"
@@ -41,26 +33,22 @@ enum Yells
enum Spells
{
- // Pure energy spell info
- SPELL_ENERGY_BOLT = 46156,
- SPELL_ENERGY_FEEDBACK = 44335,
-
- // Vexallus spell info
SPELL_CHAIN_LIGHTNING = 44318,
- SPELL_H_CHAIN_LIGHTNING = 46380, // heroic spell
SPELL_OVERLOAD = 44353,
SPELL_ARCANE_SHOCK = 44319,
- SPELL_H_ARCANE_SHOCK = 46381, // heroic spell
SPELL_SUMMON_PURE_ENERGY = 44322, // mod scale -10
H_SPELL_SUMMON_PURE_ENERGY1 = 46154, // mod scale -5
H_SPELL_SUMMON_PURE_ENERGY2 = 46159 // mod scale -5
-
};
-enum Creatures
+enum Events
{
- NPC_PURE_ENERGY = 24745,
+ EVENT_ENERGY_BOLT = 1,
+ EVENT_ENERGY_FEEDBACK,
+ EVENT_CHAIN_LIGHTNING,
+ EVENT_OVERLOAD,
+ EVENT_ARCANE_SHOCK
};
enum Misc
@@ -71,170 +59,160 @@ enum Misc
class boss_vexallus : public CreatureScript
{
-public:
- boss_vexallus() : CreatureScript("boss_vexallus") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_vexallusAI>(creature);
- };
-
- struct boss_vexallusAI : public BossAI
- {
- boss_vexallusAI(Creature* creature) : BossAI(creature, DATA_VEXALLUS_EVENT)
- {
- instance = creature->GetInstanceScript();
- }
-
- InstanceScript* instance;
+ public:
+ boss_vexallus() : CreatureScript("boss_vexallus") { }
- uint32 ChainLightningTimer;
- uint32 ArcaneShockTimer;
- uint32 OverloadTimer;
- uint32 IntervalHealthAmount;
- bool Enraged;
-
- void Reset() override
+ struct boss_vexallusAI : public BossAI
{
- summons.DespawnAll();
- ChainLightningTimer = 8000;
- ArcaneShockTimer = 5000;
- OverloadTimer = 1200;
- IntervalHealthAmount = 1;
- Enraged = false;
-
- instance->SetData(DATA_VEXALLUS_EVENT, NOT_STARTED);
- }
+ boss_vexallusAI(Creature* creature) : BossAI(creature, DATA_VEXALLUS)
+ {
+ _intervalHealthAmount = 1;
+ _enraged = false;
+ }
- void KilledUnit(Unit* /*victim*/) override
- {
- Talk(SAY_KILL);
- }
+ void Reset() override
+ {
+ _Reset();
+ _intervalHealthAmount = 1;
+ _enraged = false;
+ }
- void JustDied(Unit* /*killer*/) override
- {
- summons.DespawnAll();
- instance->SetData(DATA_VEXALLUS_EVENT, DONE);
- }
+ void KilledUnit(Unit* /*victim*/) override
+ {
+ Talk(SAY_KILL);
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ }
- instance->SetData(DATA_VEXALLUS_EVENT, IN_PROGRESS);
- }
+ void EnterCombat(Unit* /*who*/) override
+ {
+ Talk(SAY_AGGRO);
+ _EnterCombat();
- void JustSummoned(Creature* summoned) override
- {
- if (Unit* temp = SelectTarget(SELECT_TARGET_RANDOM, 0))
- summoned->GetMotionMaster()->MoveFollow(temp, 0, 0);
+ events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 8000);
+ events.ScheduleEvent(EVENT_ARCANE_SHOCK, 5000);
+ }
- //spells are SUMMON_TYPE_GUARDIAN, so using setOwner should be ok
- summoned->CastSpell(summoned, SPELL_ENERGY_BOLT, false, 0, 0, me->GetGUID());
- }
+ void JustSummoned(Creature* summoned) override
+ {
+ if (Unit* temp = SelectTarget(SELECT_TARGET_RANDOM, 0))
+ summoned->GetMotionMaster()->MoveFollow(temp, 0, 0);
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ summons.Summon(summoned);
+ }
- if (!Enraged)
+ void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override
{
- //used for check, when Vexallus cast adds 85%, 70%, 55%, 40%, 25%
- if (!HealthAbovePct(100 - INTERVAL_MODIFIER * IntervalHealthAmount))
+ if (_enraged)
+ return;
+
+ // 85%, 70%, 55%, 40%, 25%
+ if (!HealthAbovePct(100 - INTERVAL_MODIFIER * _intervalHealthAmount))
{
- //increase amount, unless we're at 10%, then we switch and return
- if (IntervalHealthAmount == INTERVAL_SWITCH)
+ // increase amount, unless we're at 10%, then we switch and return
+ if (_intervalHealthAmount == INTERVAL_SWITCH)
{
- Enraged = true;
+ _enraged = true;
+ events.Reset();
+ events.ScheduleEvent(EVENT_OVERLOAD, 1200);
return;
}
else
- ++IntervalHealthAmount;
+ ++_intervalHealthAmount;
Talk(SAY_ENERGY);
Talk(EMOTE_DISCHARGE_ENERGY);
if (IsHeroic())
{
- DoCast(me, H_SPELL_SUMMON_PURE_ENERGY1, false);
- DoCast(me, H_SPELL_SUMMON_PURE_ENERGY2, false);
+ DoCast(me, H_SPELL_SUMMON_PURE_ENERGY1);
+ DoCast(me, H_SPELL_SUMMON_PURE_ENERGY2);
}
else
- DoCast(me, SPELL_SUMMON_PURE_ENERGY, false);
-
- //below are workaround summons, remove when summoning spells w/implicitTarget 73 implemented in the core
- me->SummonCreature(NPC_PURE_ENERGY, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0);
-
- if (IsHeroic())
- me->SummonCreature(NPC_PURE_ENERGY, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0);
+ DoCast(me, SPELL_SUMMON_PURE_ENERGY);
}
+ }
- if (ChainLightningTimer <= diff)
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
- DoCast(target, SPELL_CHAIN_LIGHTNING);
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- ChainLightningTimer = 8000;
- } else ChainLightningTimer -= diff;
+ events.Update(diff);
- if (ArcaneShockTimer <= diff)
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
- if (target)
- DoCast(target, SPELL_ARCANE_SHOCK);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- ArcaneShockTimer = 8000;
- } else ArcaneShockTimer -= diff;
- }
- else
- {
- if (OverloadTimer <= diff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- DoCastVictim(SPELL_OVERLOAD);
+ switch (eventId)
+ {
+ case EVENT_CHAIN_LIGHTNING:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
+ DoCast(target, SPELL_CHAIN_LIGHTNING);
+ events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 8000);
+ break;
+ case EVENT_ARCANE_SHOCK:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, true))
+ DoCast(target, SPELL_ARCANE_SHOCK);
+ events.ScheduleEvent(EVENT_ARCANE_SHOCK, 8000);
+ break;
+ case EVENT_OVERLOAD:
+ DoCastVictim(SPELL_OVERLOAD);
+ events.ScheduleEvent(EVENT_OVERLOAD, 2000);
+ break;
+ default:
+ break;
+ }
+ }
- OverloadTimer = 2000;
- } else OverloadTimer -= diff;
+ DoMeleeAttackIfReady();
}
- DoMeleeAttackIfReady();
- }
- };
+ private:
+ uint32 _intervalHealthAmount;
+ bool _enraged;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_vexallusAI>(creature);
+ };
};
-class npc_pure_energy : public CreatureScript
+enum NpcPureEnergy
{
-public:
- npc_pure_energy() : CreatureScript("npc_pure_energy") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_pure_energyAI(creature);
- };
-
- struct npc_pure_energyAI : public ScriptedAI
- {
- npc_pure_energyAI(Creature* creature) : ScriptedAI(creature)
- {
- me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
- }
+ SPELL_ENERGY_BOLT = 46156,
+ SPELL_ENERGY_FEEDBACK = 44335,
+ SPELL_PURE_ENERGY_PASSIVE = 44326
+};
- void Reset() override { }
+class npc_pure_energy : public CreatureScript
+{
+ public:
+ npc_pure_energy() : CreatureScript("npc_pure_energy") { }
- void JustDied(Unit* slayer) override
+ struct npc_pure_energyAI : public ScriptedAI
{
- if (Unit* temp = me->GetOwner())
+ npc_pure_energyAI(Creature* creature) : ScriptedAI(creature)
{
- if (temp && temp->IsAlive())
- slayer->CastSpell(slayer, SPELL_ENERGY_FEEDBACK, true, 0, 0, temp->GetGUID());
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
}
- }
- void EnterCombat(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
+ void JustDied(Unit* killer) override
+ {
+ killer->CastSpell(killer, SPELL_ENERGY_FEEDBACK, true);
+ me->RemoveAurasDueToSpell(SPELL_PURE_ENERGY_PASSIVE);
+ }
+ };
- void AttackStart(Unit* /*who*/) override { }
- };
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_pure_energyAI(creature);
+ };
};
void AddSC_boss_vexallus()
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp
index daea647609d..e0050420a08 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -16,19 +15,10 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Instance_Magisters_Terrace
-SD%Complete: 60
-SDComment: Designed only for Selin Fireheart
-SDCategory: Magister's Terrace
-EndScriptData */
-
#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "magisters_terrace.h"
-#define MAX_ENCOUNTER 4
-
/*
0 - Selin Fireheart
1 - Vexallus
@@ -36,281 +26,239 @@ EndScriptData */
3 - Kael'thas Sunstrider
*/
-enum Creatures
+DoorData const doorData[] =
{
- NPC_SELIN = 24723,
- NPC_DELRISSA = 24560,
- NPC_FELCRYSTALS = 24722
-};
-
-enum GameObjects
-{
- GO_VEXALLUS_DOOR = 187896,
- GO_SELIN_DOOR = 187979,
- GO_SELIN_ENCOUNTER_DOOR = 188065,
- GO_DELRISSA_DOOR = 187770,
- GO_KAEL_DOOR = 188064,
- GO_KAEL_STATUE_1 = 188165,
- GO_KAEL_STATUE_2 = 188166,
- GO_ESCAPE_ORB = 188173
+ { GO_SELIN_DOOR, DATA_SELIN, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { GO_SELIN_ENCOUNTER_DOOR, DATA_SELIN, DOOR_TYPE_ROOM, BOUNDARY_NONE },
+ { GO_VEXALLUS_DOOR, DATA_VEXALLUS, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { GO_DELRISSA_DOOR, DATA_DELRISSA, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { GO_KAEL_DOOR, DATA_KAELTHAS, DOOR_TYPE_ROOM, BOUNDARY_NONE },
+ { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END
};
class instance_magisters_terrace : public InstanceMapScript
{
-public:
- instance_magisters_terrace() : InstanceMapScript("instance_magisters_terrace", 585) { }
-
- struct instance_magisters_terrace_InstanceMapScript : public InstanceScript
- {
- instance_magisters_terrace_InstanceMapScript(Map* map) : InstanceScript(map) { }
-
- uint32 Encounter[MAX_ENCOUNTER];
- uint32 DelrissaDeathCount;
+ public:
+ instance_magisters_terrace() : InstanceMapScript("instance_magisters_terrace", 585) { }
- std::vector<uint64> FelCrystals;
-
- uint64 SelinGUID;
- uint64 DelrissaGUID;
- uint64 VexallusDoorGUID;
- uint64 SelinDoorGUID;
- uint64 SelinEncounterDoorGUID;
- uint64 DelrissaDoorGUID;
- uint64 KaelDoorGUID;
- uint64 KaelStatue[2];
- uint64 EscapeOrbGUID;
- uint32 StatuesState;
- uint8 felCristalIndex;
-
- void Initialize() override
+ struct instance_magisters_terrace_InstanceMapScript : public InstanceScript
{
- memset(&Encounter, 0, sizeof(Encounter));
-
- FelCrystals.clear();
+ instance_magisters_terrace_InstanceMapScript(Map* map) : InstanceScript(map)
+ {
+ SetBossNumber(EncounterCount);
+ LoadDoorData(doorData);
- DelrissaDeathCount = 0;
+ FelCrystals.clear();
+ DelrissaDeathCount = 0;
- SelinGUID = 0;
- DelrissaGUID = 0;
- VexallusDoorGUID = 0;
- SelinDoorGUID = 0;
- SelinEncounterDoorGUID = 0;
- DelrissaDoorGUID = 0;
- KaelDoorGUID = 0;
- KaelStatue[0] = 0;
- KaelStatue[1] = 0;
- EscapeOrbGUID = 0;
- StatuesState = 0;
- felCristalIndex = 0;
- }
+ SelinGUID = 0;
+ DelrissaGUID = 0;
+ EscapeOrbGUID = 0;
+ FelCristalIndex = 0;
- bool IsEncounterInProgress() const override
- {
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (Encounter[i] == IN_PROGRESS)
- return true;
- return false;
- }
+ memset(KaelStatue, 0, 2 * sizeof(uint64));
+ }
- uint32 GetData(uint32 identifier) const
- {
- switch (identifier)
+ uint32 GetData(uint32 type) const override
{
- case DATA_SELIN_EVENT:
- return Encounter[0];
- case DATA_VEXALLUS_EVENT:
- return Encounter[1];
- case DATA_DELRISSA_EVENT:
- return Encounter[2];
- case DATA_KAELTHAS_EVENT:
- return Encounter[3];
- case DATA_DELRISSA_DEATH_COUNT:
- return DelrissaDeathCount;
- case DATA_FEL_CRYSTAL_SIZE:
- return FelCrystals.size();
+ switch (type)
+ {
+ case DATA_DELRISSA_DEATH_COUNT:
+ return DelrissaDeathCount;
+ case DATA_FEL_CRYSTAL_SIZE:
+ return uint32(FelCrystals.size());
+ default:
+ break;
+ }
+ return 0;
}
- return 0;
- }
- void SetData(uint32 identifier, uint32 data)
- {
- switch (identifier)
+ void SetData(uint32 type, uint32 data) override
{
- case DATA_SELIN_EVENT:
- if (data == DONE)
- {
- HandleGameObject(SelinEncounterDoorGUID, true);
- HandleGameObject(SelinDoorGUID, true);
- }
- else if (data == IN_PROGRESS)
- HandleGameObject(SelinEncounterDoorGUID, false);
- else if (data == NOT_STARTED)
- HandleGameObject(SelinEncounterDoorGUID, true);
-
- Encounter[0] = data;
- break;
- case DATA_VEXALLUS_EVENT:
- if (data == DONE)
- HandleGameObject(VexallusDoorGUID, true);
- Encounter[1] = data;
- break;
- case DATA_DELRISSA_EVENT:
- if (data == DONE)
- HandleGameObject(DelrissaDoorGUID, true);
- if (data == IN_PROGRESS)
- DelrissaDeathCount = 0;
- Encounter[2] = data;
- break;
- case DATA_KAELTHAS_EVENT:
- if (data == NOT_STARTED || data == DONE)
- HandleGameObject(KaelDoorGUID, true);
- else if (data == IN_PROGRESS)
- HandleGameObject(KaelDoorGUID, false);
- Encounter[3] = data;
- break;
- case DATA_DELRISSA_DEATH_COUNT:
- if (data == SPECIAL)
- ++DelrissaDeathCount;
- else
- DelrissaDeathCount = 0;
- break;
- case DATA_KAELTHAS_STATUES:
- HandleGameObject(KaelStatue[0], data);
- HandleGameObject(KaelStatue[1], data);
- StatuesState = data;
- break;
+ switch (type)
+ {
+ case DATA_DELRISSA_DEATH_COUNT:
+ if (data == SPECIAL)
+ ++DelrissaDeathCount;
+ else
+ DelrissaDeathCount = 0;
+ break;
+ case DATA_KAELTHAS_STATUES:
+ HandleGameObject(KaelStatue[0], data);
+ HandleGameObject(KaelStatue[1], data);
+ break;
+ default:
+ break;
+ }
}
- SaveToDB();
- }
-
- void OnCreatureCreate(Creature* creature) override
- {
- switch (creature->GetEntry())
+ void OnCreatureCreate(Creature* creature) override
{
- case NPC_SELIN:
- SelinGUID = creature->GetGUID();
- break;
- case NPC_DELRISSA:
- DelrissaGUID = creature->GetGUID();
- break;
- case NPC_FELCRYSTALS:
- FelCrystals.push_back(creature->GetGUID());
- break;
+ switch (creature->GetEntry())
+ {
+ case NPC_SELIN:
+ SelinGUID = creature->GetGUID();
+ break;
+ case NPC_DELRISSA:
+ DelrissaGUID = creature->GetGUID();
+ break;
+ case NPC_FELCRYSTALS:
+ FelCrystals.push_back(creature->GetGUID());
+ break;
+ default:
+ break;
+ }
}
- }
- void OnGameObjectCreate(GameObject* go) override
- {
- switch (go->GetEntry())
+ void OnGameObjectCreate(GameObject* go) override
{
- case GO_VEXALLUS_DOOR:
- VexallusDoorGUID = go->GetGUID();
- break;
- case GO_SELIN_DOOR:
- SelinDoorGUID = go->GetGUID();
- break;
- case GO_SELIN_ENCOUNTER_DOOR:
- SelinEncounterDoorGUID = go->GetGUID();
- break;
- case GO_DELRISSA_DOOR:
- DelrissaDoorGUID = go->GetGUID();
- break;
- case GO_KAEL_DOOR:
- KaelDoorGUID = go->GetGUID();
- break;
- case GO_KAEL_STATUE_1:
- KaelStatue[0] = go->GetGUID();
- break;
- case GO_KAEL_STATUE_2:
- KaelStatue[1] = go->GetGUID();
- break;
- case GO_ESCAPE_ORB:
- EscapeOrbGUID = go->GetGUID();
- break;
+ switch (go->GetEntry())
+ {
+ case GO_VEXALLUS_DOOR:
+ case GO_SELIN_DOOR:
+ case GO_SELIN_ENCOUNTER_DOOR:
+ case GO_DELRISSA_DOOR:
+ case GO_KAEL_DOOR:
+ AddDoor(go, true);
+ break;
+ case GO_KAEL_STATUE_1:
+ KaelStatue[0] = go->GetGUID();
+ break;
+ case GO_KAEL_STATUE_2:
+ KaelStatue[1] = go->GetGUID();
+ break;
+ case GO_ESCAPE_ORB:
+ EscapeOrbGUID = go->GetGUID();
+ break;
+ default:
+ break;
+ }
}
- }
-
- std::string GetSaveData() override
- {
- OUT_SAVE_INST_DATA;
-
- std::ostringstream saveStream;
- saveStream << Encounter[0] << ' ' << Encounter[1] << ' ' << Encounter[2] << ' ' << Encounter[3] << ' ' << StatuesState;
- OUT_SAVE_INST_DATA_COMPLETE;
- return saveStream.str();
- }
+ void OnGameObjectRemove(GameObject* go) override
+ {
+ switch (go->GetEntry())
+ {
+ case GO_VEXALLUS_DOOR:
+ case GO_SELIN_DOOR:
+ case GO_SELIN_ENCOUNTER_DOOR:
+ case GO_DELRISSA_DOOR:
+ case GO_KAEL_DOOR:
+ AddDoor(go, false);
+ break;
+ default:
+ break;
+ }
+ }
- void Load(const char* str) override
- {
- if (!str)
+ bool SetBossState(uint32 type, EncounterState state) override
{
- OUT_LOAD_INST_DATA_FAIL;
- return;
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
+
+ switch (type)
+ {
+ case DATA_DELRISSA:
+ if (type == IN_PROGRESS)
+ DelrissaDeathCount = 0;
+ break;
+ default:
+ break;
+ }
+ return true;
}
- OUT_LOAD_INST_DATA(str);
+ std::string GetSaveData() override
+ {
+ OUT_SAVE_INST_DATA;
- std::istringstream loadStream(str);
+ std::ostringstream saveStream;
+ saveStream << "M T " << GetBossSaveData();
- for (uint32 i = 0; i < MAX_ENCOUNTER; ++i)
- {
- uint32 tmpState;
- loadStream >> tmpState;
- if (tmpState == IN_PROGRESS || tmpState > SPECIAL)
- tmpState = NOT_STARTED;
- SetData(i, tmpState);
+ OUT_SAVE_INST_DATA_COMPLETE;
+ return saveStream.str();
}
- loadStream >> StatuesState;
- SetData(DATA_KAELTHAS_STATUES, StatuesState);
+ void Load(const char* str) override
+ {
+ if (!str)
+ {
+ OUT_LOAD_INST_DATA_FAIL;
+ return;
+ }
- OUT_LOAD_INST_DATA_COMPLETE;
- }
+ OUT_LOAD_INST_DATA(str);
- uint64 GetData64(uint32 identifier) const
- {
- switch (identifier)
- {
- case DATA_SELIN:
- return SelinGUID;
- case DATA_DELRISSA:
- return DelrissaGUID;
- case DATA_VEXALLUS_DOOR:
- return VexallusDoorGUID;
- case DATA_DELRISSA_DOOR:
- return DelrissaDoorGUID;
- case DATA_KAEL_DOOR:
- return KaelDoorGUID;
- case DATA_KAEL_STATUE_LEFT:
- return KaelStatue[0];
- case DATA_KAEL_STATUE_RIGHT:
- return KaelStatue[1];
- case DATA_ESCAPE_ORB:
- return EscapeOrbGUID;
- case DATA_FEL_CRYSTAL:
- if (FelCrystals.size() < felCristalIndex)
+ char dataHead1, dataHead2;
+
+ std::istringstream loadStream(str);
+ loadStream >> dataHead1 >> dataHead2;
+ if (dataHead1 == 'M' && dataHead2 == 'T')
+ {
+ for (uint32 i = 0; i < EncounterCount; ++i)
{
- TC_LOG_ERROR("scripts", "Magisters Terrace: No Fel Crystals loaded in Inst Data");
- return 0;
+ uint32 tmpState;
+ loadStream >> tmpState;
+ if (tmpState == IN_PROGRESS || tmpState > SPECIAL)
+ tmpState = NOT_STARTED;
+ SetBossState(i, EncounterState(tmpState));
}
+ }
+ else
+ OUT_LOAD_INST_DATA_FAIL;
- return FelCrystals.at(felCristalIndex);
+ OUT_LOAD_INST_DATA_COMPLETE;
+ }
+
+ uint64 GetData64(uint32 type) const override
+ {
+ switch (type)
+ {
+ case DATA_SELIN:
+ return SelinGUID;
+ case DATA_DELRISSA:
+ return DelrissaGUID;
+ case DATA_KAEL_STATUE_LEFT:
+ return KaelStatue[0];
+ case DATA_KAEL_STATUE_RIGHT:
+ return KaelStatue[1];
+ case DATA_ESCAPE_ORB:
+ return EscapeOrbGUID;
+ case DATA_FEL_CRYSTAL:
+ if (FelCrystals.size() < FelCristalIndex)
+ {
+ TC_LOG_ERROR("scripts", "Magisters Terrace: No Fel Crystals loaded in Inst Data");
+ return 0;
+ }
+
+ return FelCrystals.at(FelCristalIndex);
+ default:
+ break;
+ }
+ return 0;
}
- return 0;
- }
- void SetData64(uint32 identifier, uint64 value)
+ void SetData64(uint32 type, uint64 value) override
+ {
+ if (type == DATA_FEL_CRYSTAL)
+ FelCristalIndex = value;
+ }
+
+ protected:
+ std::vector<uint64> FelCrystals;
+
+ uint64 SelinGUID;
+ uint64 DelrissaGUID;
+ uint64 KaelStatue[2];
+ uint64 EscapeOrbGUID;
+ uint32 DelrissaDeathCount;
+ uint8 FelCristalIndex;
+ };
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
- if (identifier == DATA_FEL_CRYSTAL)
- felCristalIndex = value;
+ return new instance_magisters_terrace_InstanceMapScript(map);
}
- };
-
- InstanceScript* GetInstanceScript(InstanceMap* map) const override
- {
- return new instance_magisters_terrace_InstanceMapScript(map);
- }
};
void AddSC_instance_magisters_terrace()
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h
index ddfaa91bc98..d3517dfccf6 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h
@@ -19,24 +19,17 @@
#ifndef DEF_MAGISTERS_TERRACE_H
#define DEF_MAGISTERS_TERRACE_H
-#define ERROR_INST_DATA "TSCR Error: Instance Data not set properly for Magister's Terrace instance (map 585). Encounters will be buggy."
+uint32 const EncounterCount = 4;
-enum Data
+enum DataTypes
{
- DATA_SELIN_EVENT,
- DATA_VEXALLUS_EVENT,
- DATA_DELRISSA_EVENT,
- DATA_KAELTHAS_EVENT,
-
DATA_SELIN,
- DATA_FEL_CRYSTAL,
- DATA_FEL_CRYSTAL_SIZE,
-
- DATA_VEXALLUS_DOOR,
+ DATA_VEXALLUS,
DATA_DELRISSA,
- DATA_DELRISSA_DOOR,
+ DATA_KAELTHAS,
- DATA_KAEL_DOOR,
+ DATA_FEL_CRYSTAL,
+ DATA_FEL_CRYSTAL_SIZE,
DATA_KAEL_STATUE_LEFT,
DATA_KAEL_STATUE_RIGHT,
@@ -45,4 +38,23 @@ enum Data
DATA_ESCAPE_ORB
};
+enum CreatureIds
+{
+ NPC_SELIN = 24723,
+ NPC_DELRISSA = 24560,
+ NPC_FELCRYSTALS = 24722
+};
+
+enum GameObjectIds
+{
+ GO_VEXALLUS_DOOR = 187896,
+ GO_SELIN_DOOR = 187979,
+ GO_SELIN_ENCOUNTER_DOOR = 188065,
+ GO_DELRISSA_DOOR = 187770,
+ GO_KAEL_DOOR = 188064,
+ GO_KAEL_STATUE_1 = 188165,
+ GO_KAEL_STATUE_2 = 188166,
+ GO_ESCAPE_ORB = 188173
+};
+
#endif
diff --git a/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp b/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp
index 8c612a11621..bc4fff4da7b 100644
--- a/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp
@@ -190,6 +190,9 @@ enum InfusedCrystal
// Quest
QUEST_POWERING_OUR_DEFENSES = 8490,
+ // Quest Credit
+ QUEST_POD_CREDIT = 16364,
+
// Says
EMOTE = 0,
@@ -266,24 +269,17 @@ public:
summoned->AI()->AttackStart(me);
}
- void JustDied(Unit* /*killer*/) override
- {
- if (PlayerGUID && !Completed)
- if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID))
- player->FailQuest(QUEST_POWERING_OUR_DEFENSES);
- }
-
void UpdateAI(uint32 diff) override
{
if (EndTimer < diff && Progress)
{
- Talk(EMOTE);
Completed = true;
if (PlayerGUID)
if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID))
- player->CompleteQuest(QUEST_POWERING_OUR_DEFENSES);
-
- me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ {
+ Talk(EMOTE, player);
+ player->KilledMonsterCredit(QUEST_POD_CREDIT);
+ }
me->RemoveCorpse();
} else EndTimer -= diff;
diff --git a/src/server/scripts/Events/CMakeLists.txt b/src/server/scripts/Events/CMakeLists.txt
index e45bc585007..3bdb6e6eac2 100644
--- a/src/server/scripts/Events/CMakeLists.txt
+++ b/src/server/scripts/Events/CMakeLists.txt
@@ -8,9 +8,11 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+file(GLOB_RECURSE sources_Events Events/*.cpp Events/*.h)
+
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
- Events/childrens_week.cpp
+ ${sources_Events}
)
message(" -> Prepared: Events")
diff --git a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
index aa9774bfd62..ee244e51b09 100644
--- a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
+++ b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
@@ -133,106 +133,6 @@ class npc_risen_husk_spirit : public CreatureScript
};
/*######
-## npc_theramor_guard
-######*/
-
-enum TheramoreGuard
-{
- QUEST_DISCREDITING_THE_DESERTERS = 11133,
-
- NPC_THERAMORE_GUARD = 4979,
-
- SPELL_DOCTORED_LEAFLET = 42725,
- SPELL_PROPAGANDIZED = 42246,
-
- SAY_QUEST1 = 0,
- SAY_QUEST2 = 1,
- SAY_QUEST3 = 2
-};
-
-#define GOSSIP_ITEM_THERAMORE_GUARD "You look like an intelligent person. Why don't you read one of these leaflets and give it some thought?"
-
-class npc_theramore_guard : public CreatureScript
-{
-public:
- npc_theramore_guard() : CreatureScript("npc_theramore_guard") { }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (player->GetQuestStatus(QUEST_DISCREDITING_THE_DESERTERS) == QUEST_STATUS_INCOMPLETE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THERAMORE_GUARD, GOSSIP_SENDER_MAIN, GOSSIP_SENDER_INFO);
-
- player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
-
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
-
- if (action == GOSSIP_SENDER_INFO)
- {
- player->CLOSE_GOSSIP_MENU();
- player->KilledMonsterCredit(NPC_THERAMORE_GUARD, 0);
- creature->AI()->Talk(SAY_QUEST1);
- creature->CastSpell(creature, SPELL_DOCTORED_LEAFLET, false);
- creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- CAST_AI(npc_theramore_guard::npc_theramore_guardAI, creature->AI())->YellTimer = 4000;
- CAST_AI(npc_theramore_guard::npc_theramore_guardAI, creature->AI())->bYellTimer = true;
- }
-
- return true;
- }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_theramore_guardAI(creature);
- }
-
- struct npc_theramore_guardAI : public ScriptedAI
- {
- npc_theramore_guardAI(Creature* creature) : ScriptedAI(creature) { }
-
- uint32 YellTimer;
- uint32 Step;
- bool bYellTimer;
-
- void Reset() override
- {
- bYellTimer = false;
- Step = 0;
- }
-
- void UpdateAI(uint32 Diff) override
- {
- if (!me->HasAura(SPELL_PROPAGANDIZED))
- me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
-
- if (bYellTimer && YellTimer <= Diff)
- {
- switch (Step)
- {
- case 0:
- Talk(SAY_QUEST2);
- YellTimer = 3000;
- ++Step;
- break;
- case 1:
- Talk(SAY_QUEST3);
- me->HandleEmoteCommand(EMOTE_ONESHOT_LAUGH);
- Step = 0;
- bYellTimer = false;
- break;
- }
- }
- else
- YellTimer -= Diff;
- }
- };
-};
-
-/*######
## npc_lady_jaina_proudmoore
######*/
@@ -772,7 +672,6 @@ void AddSC_dustwallow_marsh()
new npc_private_hendel();
new npc_zelfrax();
new npc_stinky();
- new npc_theramore_guard();
new spell_ooze_zap();
new spell_ooze_zap_channel_end();
new spell_energize_aoe();
diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp
index 4aa59e72556..bf7b4355ea6 100644
--- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp
@@ -141,9 +141,9 @@ class instance_ahnkahet : public InstanceMapScript
SwitchTrigger = data;
break;
case DATA_JEDOGA_RESET_INITIANDS:
- for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr)
+ for (uint64 guid : InitiandGUIDs)
{
- if (Creature* creature = instance->GetCreature(*itr))
+ if (Creature* creature = instance->GetCreature(guid))
{
creature->Respawn();
if (!creature->IsInEvadeMode())
@@ -164,9 +164,9 @@ class instance_ahnkahet : public InstanceMapScript
case DATA_SPHERE_2:
return SpheresState[type - DATA_SPHERE_1];
case DATA_ALL_INITIAND_DEAD:
- for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr)
+ for (uint64 guid : InitiandGUIDs)
{
- Creature* cr = instance->GetCreature(*itr);
+ Creature* cr = instance->GetCreature(guid);
if (!cr || cr->IsAlive())
return 0;
}
@@ -214,11 +214,11 @@ class instance_ahnkahet : public InstanceMapScript
{
std::vector<uint64> vInitiands;
vInitiands.clear();
- for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr)
+ for (uint64 guid : InitiandGUIDs)
{
- Creature* cr = instance->GetCreature(*itr);
+ Creature* cr = instance->GetCreature(guid);
if (cr && cr->IsAlive())
- vInitiands.push_back(*itr);
+ vInitiands.push_back(guid);
}
if (vInitiands.empty())
return 0;
@@ -245,9 +245,9 @@ class instance_ahnkahet : public InstanceMapScript
case DATA_JEDOGA_SHADOWSEEKER:
if (state == DONE)
{
- for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr)
+ for (uint64 guid : InitiandGUIDs)
{
- if (Creature* cr = instance->GetCreature(*itr))
+ if (Creature* cr = instance->GetCreature(guid))
cr->DespawnOrUnsummon();
}
}
diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt
index aff3c0a9528..8401ea4b9a5 100644
--- a/src/server/scripts/Northrend/CMakeLists.txt
+++ b/src/server/scripts/Northrend/CMakeLists.txt
@@ -20,7 +20,6 @@ set(scripts_STAT_SRCS
Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
Northrend/Ulduar/HallsOfLightning/boss_loken.cpp
Northrend/Ulduar/Ulduar/boss_general_vezax.cpp
- Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp
Northrend/Ulduar/Ulduar/boss_thorim.cpp
Northrend/Ulduar/Ulduar/boss_ignis.cpp
Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
index f352b4faace..43c295d5f64 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
@@ -855,7 +855,6 @@ class npc_halion_controller : public CreatureScript
{
if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(itr)))
{
- RemoveCorporeality(halion, itr == DATA_TWILIGHT_HALION);
halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), true);
if (itr == DATA_TWILIGHT_HALION)
@@ -866,19 +865,6 @@ class npc_halion_controller : public CreatureScript
}
}
- void RemoveCorporeality(Creature* who, bool isTwilight = false)
- {
- for (uint8 i = 0; i < MAX_CORPOREALITY_STATE; i++)
- {
- uint32 spellID = (isTwilight ? _corporealityReference[i].twilightRealmSpell : _corporealityReference[i].materialRealmSpell);
- if (who->HasAura(spellID))
- {
- who->RemoveAurasDueToSpell(spellID);
- break;
- }
- }
- }
-
uint32 GetSpell(uint8 pctValue, bool isTwilight = false) const
{
CorporealityEntry entry = _corporealityReference[pctValue];
diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp
index 63b1359a406..4e9462a447f 100644
--- a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp
+++ b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp
@@ -208,7 +208,7 @@ public:
{
for (uint8 i = 0; i < 4; i++)
if (uint64 guid = instance->GetData64(summoners[i].data))
- if (Creature* crystalChannelTarget = instance->instance->GetCreature(guid))
+ if (Creature* crystalChannelTarget = ObjectAccessor::GetCreature(*me, guid))
{
if (active)
crystalChannelTarget->AI()->SetData(summoners[i].spell, summoners[i].timer);
@@ -221,7 +221,7 @@ public:
{
for (uint8 i = 0; i < 4; i++)
if (uint64 guid = instance->GetData64(DATA_NOVOS_CRYSTAL_1 + i))
- if (GameObject* crystal = instance->instance->GetGameObject(guid))
+ if (GameObject* crystal = ObjectAccessor::GetGameObject(*me, guid))
SetCrystalStatus(crystal, active);
}
@@ -241,7 +241,7 @@ public:
{
for (uint8 i = 0; i < 4; i++)
if (uint64 guid = instance->GetData64(DATA_NOVOS_CRYSTAL_1 + i))
- if (GameObject* crystal = instance->instance->GetGameObject(guid))
+ if (GameObject* crystal = ObjectAccessor::GetGameObject(*me, guid))
if (crystal->GetGoState() == GO_STATE_ACTIVE)
{
SetCrystalStatus(crystal, false);
@@ -258,7 +258,7 @@ public:
events.ScheduleEvent(EVENT_SUMMON_MINIONS, 15000);
}
else if (uint64 guid = instance->GetData64(DATA_NOVOS_SUMMONER_4))
- if (Creature* crystalChannelTarget = instance->instance->GetCreature(guid))
+ if (Creature* crystalChannelTarget = ObjectAccessor::GetCreature(*me, guid))
crystalChannelTarget->AI()->SetData(SPELL_SUMMON_CRYSTAL_HANDLER, 15000);
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
index 16d1531e890..e1658e564ec 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
@@ -1227,9 +1227,9 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader
if (targets.empty())
return;
- // select one random target, with preference of ranged targets
+ // select one random target, preferring ranged targets
uint32 targetsAtRange = 0;
- uint32 const minTargets = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 10 : 4);
+ uint32 const minTargets = uint32(GetCaster()->GetMap()->Is25ManRaid() ? 10 : 4);
targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false));
// get target count at range
@@ -1237,18 +1237,12 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader
if ((*itr)->GetDistance(GetCaster()) < 12.0f)
break;
- // set the upper cap
+ // If not enough ranged targets are present just select anyone
if (targetsAtRange < minTargets)
- targetsAtRange = std::min<uint32>(targets.size() - 1, minTargets);
-
- if (!targetsAtRange)
- {
- targets.clear();
- return;
- }
+ targetsAtRange = uint32(targets.size());
std::list<WorldObject*>::const_iterator itr = targets.begin();
- std::advance(itr, urand(0, targetsAtRange));
+ std::advance(itr, urand(0, targetsAtRange - 1));
target = *itr;
targets.clear();
targets.push_back(target);
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 223f3731032..b72b953efb4 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
@@ -559,6 +559,11 @@ class boss_the_lich_king : public CreatureScript
Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset);
me->VisitNearbyGridObject(333.0f, worker);
+ // Restore Tirion's gossip only after The Lich King fully resets to prevent
+ // restarting the encounter while LK still runs back to spawn point
+ if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING)))
+ tirion->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+
// Reset any light override
me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, 0, 5000);
}
@@ -1201,11 +1206,6 @@ class npc_tirion_fordring_tft : public CreatureScript
void JustReachedHome() override
{
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
-
- if (_instance->GetBossState(DATA_THE_LICH_KING) == DONE)
- return;
-
- me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
}
void UpdateAI(uint32 diff) override
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
index d3b4a285af6..d4f00414b7d 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
@@ -120,7 +120,6 @@ public:
}
void MoveInLineOfSight(Unit* who) override
-
{
if (!hasTaunted && me->IsWithinDistInMap(who, 60.0f) && who->GetTypeId() == TYPEID_PLAYER)
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp
index 02bafa8d10d..3d42827c0a8 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp
@@ -84,7 +84,6 @@ class boss_faerlina : public CreatureScript
}
void MoveInLineOfSight(Unit* who) override
-
{
if (!_introDone && who->GetTypeId() == TYPEID_PLAYER)
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp
index 3a0e3ce7c73..381be8d5cd1 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp
@@ -70,7 +70,6 @@ public:
}
void MoveInLineOfSight(Unit* who) override
-
{
if (who->GetEntry() == NPC_ZOMBIE && me->IsWithinDistInMap(who, 7))
{
diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
index 1331c25de17..e8ed181da5a 100644
--- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
@@ -368,9 +368,9 @@ class instance_naxxramas : public InstanceMapScript
if (i == section)
continue;
- for (std::set<uint64>::const_iterator itr = HeiganEruptionGUID[i].begin(); itr != HeiganEruptionGUID[i].end(); ++itr)
+ for (uint64 guid : HeiganEruptionGUID[i])
{
- if (GameObject* heiganEruption = instance->GetGameObject(*itr))
+ if (GameObject* heiganEruption = instance->GetGameObject(guid))
{
heiganEruption->SendCustomAnim(heiganEruption->GetGoAnimProgress());
heiganEruption->CastSpell(NULL, SPELL_ERUPTION);
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
index bf84a267a27..2b15ddf32c4 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
@@ -281,8 +281,8 @@ class instance_oculus : public InstanceMapScript
void GreaterWhelps()
{
- for (std::list<uint64>::const_iterator itr = GreaterWhelpList.begin(); itr != GreaterWhelpList.end(); ++itr)
- if (Creature* gwhelp = instance->GetCreature(*itr))
+ for (uint64 guid : GreaterWhelpList)
+ if (Creature* gwhelp = instance->GetCreature(guid))
gwhelp->SetPhaseMask(1, true);
}
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp
index 24d145f097f..13ea815febc 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp
@@ -164,11 +164,9 @@ public:
for (uint8 i = 0; i < 2; ++i)
{
- if (Creature* pStormforgedLieutenant = (ObjectAccessor::GetCreature((*me), m_auiStormforgedLieutenantGUID[i])))
- {
+ if (Creature* pStormforgedLieutenant = ObjectAccessor::GetCreature(*me, m_auiStormforgedLieutenantGUID[i]))
if (!pStormforgedLieutenant->IsAlive())
pStormforgedLieutenant->Respawn();
- }
}
if (m_uiStance != STANCE_DEFENSIVE)
@@ -411,7 +409,7 @@ public:
void EnterCombat(Unit* who) override
{
- if (Creature* pBjarngrim = instance->instance->GetCreature(instance->GetData64(DATA_BJARNGRIM)))
+ if (Creature* pBjarngrim = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BJARNGRIM)))
{
if (pBjarngrim->IsAlive() && !pBjarngrim->GetVictim())
pBjarngrim->AI()->AttackStart(who);
@@ -434,7 +432,7 @@ public:
if (m_uiRenewSteel_Timer <= uiDiff)
{
- if (Creature* pBjarngrim = instance->instance->GetCreature(instance->GetData64(DATA_BJARNGRIM)))
+ if (Creature* pBjarngrim = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BJARNGRIM)))
{
if (pBjarngrim->IsAlive())
DoCast(pBjarngrim, SPELL_RENEW_STEEL_N);
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp
index aac315cda0d..83082b18d73 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp
@@ -165,9 +165,9 @@ public:
Position pos = me->GetPosition();
- for (std::list<uint64>::const_iterator itr = lSparkList.begin(); itr != lSparkList.end(); ++itr)
+ for (uint64 guid : lSparkList)
{
- if (Creature* pSpark = ObjectAccessor::GetCreature(*me, *itr))
+ if (Creature* pSpark = ObjectAccessor::GetCreature(*me, guid))
{
if (pSpark->IsAlive())
{
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
index d0b8f75e711..b424ce01b06 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
@@ -162,13 +162,11 @@ public:
if (m_lGolemGUIDList.empty())
return;
- for (std::list<uint64>::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr)
+ for (uint64 guid : m_lGolemGUIDList)
{
- if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr))
- {
+ if (Creature* temp = ObjectAccessor::GetCreature(*me, guid))
if (temp->IsAlive())
temp->DespawnOrUnsummon();
- }
}
m_lGolemGUIDList.clear();
@@ -179,9 +177,9 @@ public:
if (m_lGolemGUIDList.empty())
return;
- for (std::list<uint64>::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr)
+ for (uint64 guid : m_lGolemGUIDList)
{
- if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr))
+ if (Creature* temp = ObjectAccessor::GetCreature(*me, guid))
{
// Only shatter brittle golems
if (temp->IsAlive() && temp->GetEntry() == NPC_BRITTLE_GOLEM)
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp
index eec08c3c429..796299cc952 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp
@@ -37,7 +37,7 @@ enum Spells
enum Events
{
- EVENT_PARTING_SORROW = 1,
+ EVENT_PARTING_SORROW = 1,
EVENT_STORM_OF_GRIEF,
EVENT_SHOCK_OF_SORROW,
EVENT_PILLAR_OF_WOE
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
index 67500382758..595dcecd554 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
@@ -334,7 +334,7 @@ class boss_algalon_the_observer : public CreatureScript
{
case ACTION_START_INTRO:
{
- me->SetFlag(UNIT_FIELD_FLAGS_2, 0x20);
+ me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_INSTANTLY_APPEAR_MODEL);
me->SetDisableGravity(true);
DoCast(me, SPELL_ARRIVAL, true);
DoCast(me, SPELL_RIDE_THE_LIGHTNING, true);
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
index 4dfa38abae5..257518d998b 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
@@ -18,9 +18,10 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "InstanceScript.h"
-#include "ulduar.h"
#include "Player.h"
#include "WorldPacket.h"
+#include "SpellScript.h"
+#include "ulduar.h"
static DoorData const doorData[] =
{
@@ -1161,7 +1162,43 @@ class instance_ulduar : public InstanceMapScript
}
};
+class spell_ulduar_teleporter : public SpellScriptLoader
+{
+ public:
+ spell_ulduar_teleporter() : SpellScriptLoader("spell_ulduar_teleporter") { }
+
+ class spell_ulduar_teleporter_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_ulduar_teleporter_SpellScript);
+
+ SpellCastResult CheckRequirement()
+ {
+ if (GetExplTargetUnit()->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_FAILED_DONT_REPORT;
+
+ if (GetExplTargetUnit()->IsInCombat())
+ {
+ Spell::SendCastResult(GetExplTargetUnit()->ToPlayer(), GetSpellInfo(), 0, SPELL_FAILED_AFFECTING_COMBAT);
+ return SPELL_FAILED_AFFECTING_COMBAT;
+ }
+
+ return SPELL_CAST_OK;
+ }
+
+ void Register() override
+ {
+ OnCheckCast += SpellCheckCastFn(spell_ulduar_teleporter_SpellScript::CheckRequirement);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_ulduar_teleporter_SpellScript();
+ }
+};
+
void AddSC_instance_ulduar()
{
new instance_ulduar();
+ new spell_ulduar_teleporter();
}
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp
deleted file mode 100644
index 9fc0e4056fa..00000000000
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * 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 "ScriptMgr.h"
-#include "ScriptedGossip.h"
-#include "InstanceScript.h"
-#include "Player.h"
-#include "ulduar.h"
-
-/*
-The teleporter appears to be active and stable.
-
-- Expedition Base Camp
-- Formation Grounds
-- Colossal Forge
-- Scrapyard
-- Antechamber of Ulduar
-- Shattered Walkway
-- Conservatory of Life
-*/
-
-enum UlduarTeleporter
-{
- BASE_CAMP = 200,
- GROUNDS = 201,
- FORGE = 202,
- SCRAPYARD = 203,
- ANTECHAMBER = 204,
- WALKWAY = 205,
- CONSERVATORY = 206,
-};
-
-class ulduar_teleporter : public GameObjectScript
-{
- public:
- ulduar_teleporter() : GameObjectScript("ulduar_teleporter") { }
-
- bool OnGossipSelect(Player* player, GameObject* /*gameObject*/, uint32 sender, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- if (sender != GOSSIP_SENDER_MAIN)
- return false;
- if (!player->getAttackers().empty())
- return false;
-
- switch (action)
- {
- case BASE_CAMP:
- player->TeleportTo(603, -706.122f, -92.6024f, 429.876f, 0.0f);
- player->CLOSE_GOSSIP_MENU();
- break;
- case GROUNDS:
- player->TeleportTo(603, 131.248f, -35.3802f, 409.804f, 0.0f);
- player->CLOSE_GOSSIP_MENU();
- break;
- case FORGE:
- player->TeleportTo(603, 553.233f, -12.3247f, 409.679f, 0.0f);
- player->CLOSE_GOSSIP_MENU();
- break;
- case SCRAPYARD:
- player->TeleportTo(603, 926.292f, -11.4635f, 418.595f, 0.0f);
- player->CLOSE_GOSSIP_MENU();
- break;
- case ANTECHAMBER:
- player->TeleportTo(603, 1498.09f, -24.246f, 420.967f, 0.0f);
- player->CLOSE_GOSSIP_MENU();
- break;
- case WALKWAY:
- player->TeleportTo(603, 1859.45f, -24.1f, 448.9f, 0.0f);
- player->CLOSE_GOSSIP_MENU();
- break;
- case CONSERVATORY:
- player->TeleportTo(603, 2086.27f, -24.3134f, 421.239f, 0.0f);
- player->CLOSE_GOSSIP_MENU();
- break;
- }
-
- return true;
- }
-
- bool OnGossipHello(Player* player, GameObject* gameObject) override
- {
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Expedition Base Camp", GOSSIP_SENDER_MAIN, BASE_CAMP);
- if (InstanceScript* instance = gameObject->GetInstanceScript())
- {
- if (instance->GetData(DATA_COLOSSUS) == 2) //count of 2 collossus death
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Formation Grounds", GOSSIP_SENDER_MAIN, GROUNDS);
- if (instance->GetBossState(BOSS_LEVIATHAN) == DONE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Colossal Forge", GOSSIP_SENDER_MAIN, FORGE);
- if (instance->GetBossState(BOSS_XT002) == DONE)
- {
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Scrapyard", GOSSIP_SENDER_MAIN, SCRAPYARD);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Antechamber of Ulduar", GOSSIP_SENDER_MAIN, ANTECHAMBER);
- }
- if (instance->GetBossState(BOSS_KOLOGARN) == DONE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Shattered Walkway", GOSSIP_SENDER_MAIN, WALKWAY);
- if (instance->GetBossState(BOSS_AURIAYA) == DONE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Conservatory of Life", GOSSIP_SENDER_MAIN, CONSERVATORY);
- }
-
- player->SEND_GOSSIP_MENU(gameObject->GetGOInfo()->GetGossipMenuId(), gameObject->GetGUID());
- return true;
- }
-};
-
-void AddSC_ulduar_teleporter()
-{
- new ulduar_teleporter();
-}
diff --git a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp
index e4bd9c469fb..7d680ecd071 100644
--- a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp
+++ b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp
@@ -76,20 +76,18 @@ public:
GetCreatureListWithEntryInGrid(orbList, me, NPC_TRANSITUS_SHIELD_DUMMY, 32.0f);
if (!orbList.empty())
{
- for (std::list<Creature*>::const_iterator itr = orbList.begin(); itr != orbList.end(); ++itr)
+ for (Creature* orb : orbList)
{
- if (Creature* pOrb = *itr)
+ if (orb->GetPositionY() < 1000)
{
- if (pOrb->GetPositionY() < 1000)
- {
- targetGUID = pOrb->GetGUID();
- break;
- }
+ targetGUID = orb->GetGUID();
+ break;
}
}
}
}
- }else
+ }
+ else
{
if (!targetGUID)
if (Creature* pOrb = GetClosestCreatureWithEntry(me, NPC_TRANSITUS_SHIELD_DUMMY, 32.0f))
diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp
index 21fc93578ae..1e8da70bbbf 100644
--- a/src/server/scripts/Northrend/zone_dalaran.cpp
+++ b/src/server/scripts/Northrend/zone_dalaran.cpp
@@ -73,7 +73,6 @@ public:
void AttackStart(Unit* /*who*/) override { }
void MoveInLineOfSight(Unit* who) override
-
{
if (!who || !who->IsInWorld() || who->GetZoneId() != 4395)
return;
diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp
index bda6d953d9f..59c9b21a220 100644
--- a/src/server/scripts/Northrend/zone_dragonblight.cpp
+++ b/src/server/scripts/Northrend/zone_dragonblight.cpp
@@ -246,13 +246,10 @@ class npc_commander_eligor_dawnbringer : public CreatureScript
{
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, me, AudienceMobs[ii], 15.0f);
- for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
+ for (Creature* creature : creatureList)
{
- if (Creature* creatureList = *itr)
- {
- audienceList[creaturecount] = creatureList->GetGUID();
- ++creaturecount;
- }
+ audienceList[creaturecount] = creature->GetGUID();
+ ++creaturecount;
}
}
diff --git a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp
index 0004df68016..f03caa37cb2 100644
--- a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp
+++ b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp
@@ -17,14 +17,14 @@
*/
/* ScriptData
-SDName: Boss_Bloodboil
-SD%Complete: 80
-SDComment: Bloodboil not working correctly, missing enrage
-SDCategory: Black Temple
+Name: Boss_Bloodboil
+Complete: 80
+Category: Black Temple
EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
#include "black_temple.h"
enum Bloodboil
@@ -54,9 +54,6 @@ enum Bloodboil
SPELL_BERSERK = 45078
};
-
-//This is used to sort the players by distance in preparation for the Bloodboil cast.
-
class boss_gurtogg_bloodboil : public CreatureScript
{
public:
@@ -137,51 +134,6 @@ public:
Talk(SAY_DEATH);
}
- // Note: This seems like a very complicated fix. The fix needs to be handled by the core, as implementation of limited-target AoE spells are still not limited.
- void CastBloodboil()
- {
- // Get the Threat List
- std::list<HostileReference*> m_threatlist = me->getThreatManager().getThreatList();
-
- if (m_threatlist.empty()) // He doesn't have anyone in his threatlist, useless to continue
- return;
-
- std::list<Unit*> targets;
- std::list<HostileReference*>::const_iterator itr = m_threatlist.begin();
- for (; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container
- {
- Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
- //only on alive players
- if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
- targets.push_back(target);
- }
-
- //Sort the list of players
- targets.sort(Trinity::ObjectDistanceOrderPred(me, false));
- //Resize so we only get top 5
- targets.resize(5);
-
- //Aura each player in the targets list with Bloodboil. Aura code copied+pasted from Aura command in Level3.cpp
- /*SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_BLOODBOIL);
- if (spellInfo)
- {
- for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
- {
- Unit* target = *itr;
- if (!target) return;
- for (uint32 i = 0; i<3; ++i)
- {
- uint8 eff = spellInfo->Effect[i];
- if (eff >= TOTAL_SPELL_EFFECTS)
- continue;
-
- Aura* Aur = new Aura(spellInfo, i, target, target, target);
- target->AddAura(Aur);
- }
- }
- }*/
- }
-
void RevertThreatOnTarget(uint64 guid)
{
if (Unit* unit = ObjectAccessor::GetUnit(*me, guid))
@@ -247,8 +199,7 @@ public:
{
if (BloodboilCount < 5) // Only cast it five times.
{
- //CastBloodboil(); // Causes issues on windows, so is commented out.
- DoCastVictim(SPELL_BLOODBOIL);
+ DoCastAOE(SPELL_BLOODBOIL);
++BloodboilCount;
BloodboilTimer = 10000*BloodboilCount;
}
@@ -274,7 +225,7 @@ public:
{
if (Phase1)
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
Phase1 = false;
@@ -327,7 +278,41 @@ public:
};
+// 42005 - Bloodboil
+class spell_gurtogg_bloodboil_bloodboil : public SpellScriptLoader
+{
+ public:
+ spell_gurtogg_bloodboil_bloodboil() : SpellScriptLoader("spell_gurtogg_bloodboil_bloodboil") { }
+
+ class spell_gurtogg_bloodboil_bloodboil_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_gurtogg_bloodboil_bloodboil_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ if (targets.size() <= 5)
+ return;
+
+ // Sort the list of players
+ targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false));
+ // Resize so we only get top 5
+ targets.resize(5);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gurtogg_bloodboil_bloodboil_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_gurtogg_bloodboil_bloodboil_SpellScript();
+ }
+};
+
void AddSC_boss_gurtogg_bloodboil()
{
new boss_gurtogg_bloodboil();
+ new spell_gurtogg_bloodboil_bloodboil();
}
diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt
index 414a3bce14a..0c69a236ef8 100644
--- a/src/server/scripts/Outland/CMakeLists.txt
+++ b/src/server/scripts/Outland/CMakeLists.txt
@@ -112,7 +112,7 @@ set(scripts_STAT_SRCS
Outland/BlackTemple/instance_black_temple.cpp
Outland/BlackTemple/boss_reliquary_of_souls.cpp
Outland/BlackTemple/boss_warlord_najentus.cpp
- Outland/BlackTemple/boss_bloodboil.cpp
+ Outland/BlackTemple/boss_gurtogg_bloodboil.cpp
Outland/BlackTemple/boss_illidan.cpp
Outland/zone_shadowmoon_valley.cpp
Outland/zone_blades_edge_mountains.cpp
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index 5ae0e1601c5..245ec7e88cf 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -39,9 +39,11 @@ enum DeathKnightSpells
SPELL_DK_DEATH_COIL_DAMAGE = 47632,
SPELL_DK_DEATH_COIL_HEAL = 47633,
SPELL_DK_DEATH_STRIKE_HEAL = 45470,
+ SPELL_DK_FROST_FEVER = 55095,
SPELL_DK_FROST_PRESENCE = 48263,
SPELL_DK_FROST_PRESENCE_TRIGGERED = 61261,
SPELL_DK_GHOUL_EXPLODE = 47496,
+ SPELL_DK_GLYPH_OF_DISEASE = 63334,
SPELL_DK_GLYPH_OF_ICEBOUND_FORTITUDE = 58625,
SPELL_DK_IMPROVED_BLOOD_PRESENCE_R1 = 50365,
SPELL_DK_IMPROVED_FROST_PRESENCE_R1 = 50384,
@@ -51,6 +53,7 @@ enum DeathKnightSpells
SPELL_DK_ITEM_SIGIL_VENGEFUL_HEART = 64962,
SPELL_DK_ITEM_T8_MELEE_4P_BONUS = 64736,
SPELL_DK_MASTER_OF_GHOULS = 52143,
+ SPELL_DK_BLOOD_PLAGUE = 55078,
SPELL_DK_RAISE_DEAD_USE_REAGENT = 48289,
SPELL_DK_RUNIC_POWER_ENERGIZE = 49088,
SPELL_DK_SCENT_OF_BLOOD = 50422,
@@ -933,6 +936,91 @@ class spell_dk_improved_unholy_presence : public SpellScriptLoader
}
};
+// ID - 50842 Pestilence
+class spell_dk_pestilence : public SpellScriptLoader
+{
+ public:
+ spell_dk_pestilence() : SpellScriptLoader("spell_dk_pestilence") { }
+
+ class spell_dk_pestilence_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_dk_pestilence_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_GLYPH_OF_DISEASE)
+ || !sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_PLAGUE)
+ || !sSpellMgr->GetSpellInfo(SPELL_DK_FROST_FEVER))
+ return false;
+ return true;
+ }
+
+ void OnHit(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+ Unit* hitUnit = GetHitUnit();
+ Unit* victim = GetExplTargetUnit();
+
+ if (!victim)
+ return;
+
+ if (victim != hitUnit || caster->HasAura(SPELL_DK_GLYPH_OF_DISEASE))
+ {
+ if (Aura* aurOld = victim->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) // Check Blood Plague application on victim.
+ {
+ if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0))
+ {
+ float donePct = aurEffOld->GetDonePct();
+ float critChance = aurEffOld->GetCritChance();
+
+ caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true); // Spread the disease to hitUnit.
+
+ if (Aura* aurNew = hitUnit->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) // Check Blood Plague application on hitUnit.
+ {
+ if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0))
+ {
+ aurEffNew->SetCritChance(critChance); // Blood Plague can crit if caster has T9.
+ aurEffNew->SetDonePct(donePct);
+ aurEffNew->SetDamage(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct);
+ }
+ }
+ }
+ }
+
+ if (Aura* aurOld = victim->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on victim.
+ {
+ if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0))
+ {
+ float donePct = aurEffOld->GetDonePct();
+
+ caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true); // Spread the disease to hitUnit.
+
+ if (Aura* aurNew = hitUnit->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on hitUnit.
+ {
+ if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0))
+ {
+ aurEffNew->SetDonePct(donePct);
+ aurEffNew->SetDamage(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_dk_pestilence_SpellScript::OnHit, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_dk_pestilence_SpellScript();
+ }
+};
+
+
// 48266 - Blood Presence
// 48263 - Frost Presence
// 48265 - Unholy Presence
@@ -1467,6 +1555,7 @@ void AddSC_deathknight_spell_scripts()
new spell_dk_improved_blood_presence();
new spell_dk_improved_frost_presence();
new spell_dk_improved_unholy_presence();
+ new spell_dk_pestilence();
new spell_dk_presence();
new spell_dk_raise_dead();
new spell_dk_rune_tap_party();
diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp
index 3f935077b22..4571798506e 100644
--- a/src/server/scripts/Spells/spell_warlock.cpp
+++ b/src/server/scripts/Spells/spell_warlock.cpp
@@ -518,7 +518,7 @@ class spell_warl_haunt : public SpellScriptLoader
{
PrepareSpellScript(spell_warl_haunt_SpellScript);
- void HandleOnHit()
+ void HandleAfterHit()
{
if (Aura* aura = GetHitAura())
if (AuraEffect* aurEff = aura->GetEffect(EFFECT_1))
@@ -527,7 +527,7 @@ class spell_warl_haunt : public SpellScriptLoader
void Register() override
{
- OnHit += SpellHitFn(spell_warl_haunt_SpellScript::HandleOnHit);
+ AfterHit += SpellHitFn(spell_warl_haunt_SpellScript::HandleAfterHit);
}
};
diff --git a/src/server/scripts/World/CMakeLists.txt b/src/server/scripts/World/CMakeLists.txt
index 7d1b46732cf..56a0a1eb4c7 100644
--- a/src/server/scripts/World/CMakeLists.txt
+++ b/src/server/scripts/World/CMakeLists.txt
@@ -8,20 +8,11 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+file(GLOB_RECURSE sources_World World/*.cpp World/*.h)
+
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
- World/achievement_scripts.cpp
- World/areatrigger_scripts.cpp
- World/boss_emerald_dragons.cpp
- World/chat_log.cpp
- World/go_scripts.cpp
- World/guards.cpp
- World/item_scripts.cpp
- World/mob_generic_creature.cpp
- World/npc_innkeeper.cpp
- World/npc_professions.cpp
- World/npc_taxi.cpp
- World/npcs_special.cpp
+ ${sources_World}
)
message(" -> Prepared: World")
diff --git a/src/server/scripts/World/action_ip_logger.cpp b/src/server/scripts/World/action_ip_logger.cpp
new file mode 100644
index 00000000000..057f3d6ee36
--- /dev/null
+++ b/src/server/scripts/World/action_ip_logger.cpp
@@ -0,0 +1,315 @@
+/*
+ * 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 "ScriptMgr.h"
+#include "Channel.h"
+#include "Guild.h"
+#include "Group.h"
+
+enum IPLoggingTypes
+{
+
+ // AccountActionIpLogger();
+ ACCOUNT_LOGIN = 0,
+ ACCOUNT_FAIL_LOGIN = 1,
+ ACCOUNT_CHANGE_PW = 2,
+ ACCOUNT_CHANGE_PW_FAIL = 3, // Only two types of account changes exist...
+ ACCOUNT_CHANGE_EMAIL = 4,
+ ACCOUNT_CHANGE_EMAIL_FAIL = 5, // ...so we log them individually
+ // OBSOLETE - ACCOUNT_LOGOUT = 6, /* Can not be logged. We still keep the type however */
+ // CharacterActionIpLogger();
+ CHARACTER_CREATE = 7,
+ CHARACTER_LOGIN = 8,
+ CHARACTER_LOGOUT = 9,
+ // CharacterDeleteActionIpLogger();
+ CHARACTER_DELETE = 10,
+ CHARACTER_FAILED_DELETE = 11,
+ // AccountActionIpLogger(), CharacterActionIpLogger(), CharacterActionIpLogger();
+ UNKNOWN_ACTION = 12
+};
+
+class AccountActionIpLogger : public AccountScript
+{
+ public:
+ AccountActionIpLogger() : AccountScript("AccountActionIpLogger") { }
+
+ // We log last_ip instead of last_attempt_ip, as login was successful
+ // ACCOUNT_LOGIN = 0
+ void OnAccountLogin(uint32 accountId) override
+ {
+ AccountIPLogAction(accountId, ACCOUNT_LOGIN);
+ }
+
+ // We log last_attempt_ip instead of last_ip, as failed login doesn't necessarily mean approperiate user
+ // ACCOUNT_FAIL_LOGIN = 1
+ void OnFailedAccountLogin(uint32 accountId) override
+ {
+ AccountIPLogAction(accountId, ACCOUNT_FAIL_LOGIN);
+ }
+
+ // ACCOUNT_CHANGE_PW = 2
+ void OnPasswordChange(uint32 accountId) override
+ {
+ AccountIPLogAction(accountId, ACCOUNT_CHANGE_PW);
+ }
+
+ // ACCOUNT_CHANGE_PW_FAIL = 3
+ void OnFailedPasswordChange(uint32 accountId) override
+ {
+ AccountIPLogAction(accountId, ACCOUNT_CHANGE_PW_FAIL);
+ }
+
+ // Registration Email can NOT be changed apart from GM level users. Thus, we do not require to log them...
+ // ACCOUNT_CHANGE_EMAIL = 4
+ void OnEmailChange(uint32 accountId) override
+ {
+ AccountIPLogAction(accountId, ACCOUNT_CHANGE_EMAIL); // ... they get logged by gm command logger anyway
+ }
+
+ // ACCOUNT_CHANGE_EMAIL_FAIL = 5
+ void OnFailedEmailChange(uint32 accountId) override
+ {
+ AccountIPLogAction(accountId, ACCOUNT_CHANGE_EMAIL_FAIL);
+ }
+
+ /* It's impossible to log the account logout process out of character selection - shouldn't matter anyway,
+ * as ip doesn't change through playing (obviously).*/
+ // ACCOUNT_LOGOUT = 6
+ void AccountIPLogAction(uint32 accountId, IPLoggingTypes aType)
+ {
+ // Action IP Logger is only intialized if config is set up
+ // Else, this script isn't loaded in the first place: We require no config check.
+
+ // We declare all the required variables
+ uint32 playerGuid = accountId;
+ uint32 characterGuid = 0;
+ std::string systemNote = "ERROR"; // "ERROR" is a placeholder here. We change it later.
+
+ // With this switch, we change systemNote so that we have a more accurate phrasing of what type it is.
+ // Avoids Magicnumbers in SQL table
+ switch (aType)
+ {
+ case ACCOUNT_LOGIN:
+ systemNote = "Logged on Successful AccountLogin";
+ break;
+ case ACCOUNT_FAIL_LOGIN:
+ systemNote = "Logged on Failed AccountLogin";
+ break;
+ case ACCOUNT_CHANGE_PW:
+ systemNote = "Logged on Successful Account Password Change";
+ break;
+ case ACCOUNT_CHANGE_PW_FAIL:
+ systemNote = "Logged on Failed Account Password Change";
+ break;
+ case ACCOUNT_CHANGE_EMAIL:
+ systemNote = "Logged on Successful Account Email Change";
+ break;
+ case ACCOUNT_CHANGE_EMAIL_FAIL:
+ systemNote = "Logged on Failed Account Email Change";
+ break;
+ /*case ACCOUNT_LOGOUT:
+ systemNote = "Logged on AccountLogout"; //Can not be logged
+ break;*/
+ // Neither should happen. Ever. Period. If it does, call Ghostbusters and all your local software defences to investigate.
+ case UNKNOWN_ACTION:
+ default:
+ systemNote = "ERROR! Unknown action!";
+ break;
+ }
+
+ // Once we have done everything, we can insert the new log.
+ // Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now;
+ // Rather, we let it be added with the SQL query.
+ if (aType != ACCOUNT_FAIL_LOGIN)
+ {
+ // As we can assume most account actions are NOT failed login, so this is the more accurate check.
+ // For those, we need last_ip...
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ALDL_IP_LOGGING);
+
+ stmt->setUInt32(0, playerGuid);
+ stmt->setUInt32(1, characterGuid);
+ stmt->setUInt8(2, aType);
+ stmt->setUInt32(3, playerGuid);
+ stmt->setString(4, systemNote.c_str());
+ LoginDatabase.Execute(stmt);
+ }
+ else // ... but for failed login, we query last_attempt_ip from account table. Which we do with an unique query
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FACL_IP_LOGGING);
+
+ stmt->setUInt32(0, playerGuid);
+ stmt->setUInt32(1, characterGuid);
+ stmt->setUInt8(2, aType);
+ stmt->setUInt32(3, playerGuid);
+ stmt->setString(4, systemNote.c_str());
+ LoginDatabase.Execute(stmt);
+ }
+ return;
+ }
+};
+
+class CharacterActionIpLogger : public PlayerScript
+{
+ public:
+ CharacterActionIpLogger() : PlayerScript("CharacterActionIpLogger") { }
+
+ // CHARACTER_CREATE = 7
+ void OnCreate(Player* player) override
+ {
+ CharacterIPLogAction(player, CHARACTER_CREATE);
+ }
+
+ // CHARACTER_LOGIN = 8
+ void OnLogin(Player* player, bool /*firstLogin*/) override
+ {
+ CharacterIPLogAction(player, CHARACTER_LOGIN);
+ }
+
+ // CHARACTER_LOGOUT = 9
+ void OnLogout(Player* player) override
+ {
+ CharacterIPLogAction(player, CHARACTER_LOGOUT);
+ }
+
+ // CHARACTER_DELETE = 10
+ // CHARACTER_FAILED_DELETE = 11
+ // We don't log either here - they require a guid
+
+ // UNKNOWN_ACTION = 12
+ // There is no real hook we could use for that.
+ // Shouldn't happen anyway, should it ? Nothing to see here.
+
+ /// Logs a number of actions done by players with an IP
+ void CharacterIPLogAction(Player* player, IPLoggingTypes aType)
+ {
+ // Action IP Logger is only intialized if config is set up
+ // Else, this script isn't loaded in the first place: We require no config check.
+
+ // We declare all the required variables
+ uint32 playerGuid = player->GetSession()->GetAccountId();
+ uint32 characterGuid = player->GetGUIDLow();
+ const std::string currentIp = player->GetSession()->GetRemoteAddress();
+ std::string systemNote = "ERROR"; // "ERROR" is a placeholder here. We change it...
+
+ // ... with this switch, so that we have a more accurate phrasing of what type it is
+ switch (aType)
+ {
+ case CHARACTER_CREATE:
+ systemNote = "Logged on CharacterCreate";
+ break;
+ case CHARACTER_LOGIN:
+ systemNote = "Logged on CharacterLogin";
+ break;
+ case CHARACTER_LOGOUT:
+ systemNote = "Logged on CharacterLogout";
+ break;
+ case CHARACTER_DELETE:
+ systemNote = "Logged on CharacterDelete";
+ break;
+ case CHARACTER_FAILED_DELETE:
+ systemNote = "Logged on Failed CharacterDelete";
+ break;
+ // Neither should happen. Ever. Period. If it does, call Mythbusters.
+ case UNKNOWN_ACTION:
+ default:
+ systemNote = "ERROR! Unknown action!";
+ break;
+ }
+
+ // Once we have done everything, we can insert the new log.
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_CHAR_IP_LOGGING);
+
+ stmt->setUInt32(0, playerGuid);
+ stmt->setUInt32(1, characterGuid);
+ stmt->setUInt8(2, aType);
+ stmt->setString(3, currentIp.c_str()); // We query the ip here.
+ stmt->setString(4, systemNote.c_str());
+ // Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now;
+ // Rather, we let it be added with the SQL query.
+
+ LoginDatabase.Execute(stmt);
+ return;
+ }
+};
+
+class CharacterDeleteActionIpLogger : public PlayerScript
+{
+public:
+ CharacterDeleteActionIpLogger() : PlayerScript("CharacterDeleteActionIpLogger") { }
+
+ // CHARACTER_DELETE = 10
+ void OnDelete(uint64 guid, uint32 accountId) override
+ {
+ DeleteIPLogAction(guid, accountId, CHARACTER_DELETE);
+ }
+
+ // CHARACTER_FAILED_DELETE = 11
+ void OnFailedDelete(uint64 guid, uint32 accountId) override
+ {
+ DeleteIPLogAction(guid, accountId, CHARACTER_FAILED_DELETE);
+ }
+
+ void DeleteIPLogAction(uint64 guid, uint32 playerGuid, IPLoggingTypes aType)
+ {
+ // Action IP Logger is only intialized if config is set up
+ // Else, this script isn't loaded in the first place: We require no config check.
+
+ // We declare all the required variables
+ uint32 characterGuid = GUID_LOPART(guid); // We have no access to any member function of Player* or WorldSession*. So use old-fashioned way.
+ // Query playerGuid/accountId, as we only have characterGuid
+ std::string systemNote = "ERROR"; // "ERROR" is a placeholder here. We change it later.
+
+ // With this switch, we change systemNote so that we have a more accurate phrasing of what type it is.
+ // Avoids Magicnumbers in SQL table
+ switch (aType)
+ {
+ case CHARACTER_DELETE:
+ systemNote = "Logged on CharacterDelete";
+ break;
+ case CHARACTER_FAILED_DELETE:
+ systemNote = "Logged on Failed CharacterDelete";
+ break;
+ // Neither should happen. Ever. Period. If it does, call to whatever god you have for mercy and guidance.
+ case UNKNOWN_ACTION:
+ default:
+ systemNote = "ERROR! Unknown action!";
+ break;
+ }
+
+ // Once we have done everything, we can insert the new log.
+ PreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_INS_ALDL_IP_LOGGING);
+
+ stmt2->setUInt32(0, playerGuid);
+ stmt2->setUInt32(1, characterGuid);
+ stmt2->setUInt8(2, aType);
+ stmt2->setUInt32(3, playerGuid);
+ stmt2->setString(4, systemNote.c_str());
+ // Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now;
+ // Rather, we let it be added with the SQL query.
+
+ LoginDatabase.Execute(stmt2);
+ return;
+ }
+};
+
+
+void AddSC_action_ip_logger()
+{
+ new AccountActionIpLogger();
+ new CharacterActionIpLogger();
+ new CharacterDeleteActionIpLogger();
+}
diff --git a/src/server/scripts/World/areatrigger_scripts.cpp b/src/server/scripts/World/areatrigger_scripts.cpp
index fb438c38efb..4393f72eb1b 100644
--- a/src/server/scripts/World/areatrigger_scripts.cpp
+++ b/src/server/scripts/World/areatrigger_scripts.cpp
@@ -51,11 +51,7 @@ enum CoilfangGOs
class AreaTrigger_at_coilfang_waterfall : public AreaTriggerScript
{
public:
-
- AreaTrigger_at_coilfang_waterfall()
- : AreaTriggerScript("at_coilfang_waterfall")
- {
- }
+ AreaTrigger_at_coilfang_waterfall() : AreaTriggerScript("at_coilfang_waterfall") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
{
@@ -83,11 +79,7 @@ enum LegionTeleporter
class AreaTrigger_at_legion_teleporter : public AreaTriggerScript
{
public:
-
- AreaTrigger_at_legion_teleporter()
- : AreaTriggerScript("at_legion_teleporter")
- {
- }
+ AreaTrigger_at_legion_teleporter() : AreaTriggerScript("at_legion_teleporter") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
{
@@ -125,11 +117,7 @@ enum StormwrightShelf
class AreaTrigger_at_stormwright_shelf : public AreaTriggerScript
{
public:
-
- AreaTrigger_at_stormwright_shelf()
- : AreaTriggerScript("at_stormwright_shelf")
- {
- }
+ AreaTrigger_at_stormwright_shelf() : AreaTriggerScript("at_stormwright_shelf") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
{
@@ -153,11 +141,7 @@ enum ScentLarkorwi
class AreaTrigger_at_scent_larkorwi : public AreaTriggerScript
{
public:
-
- AreaTrigger_at_scent_larkorwi()
- : AreaTriggerScript("at_scent_larkorwi")
- {
- }
+ AreaTrigger_at_scent_larkorwi() : AreaTriggerScript("at_scent_larkorwi") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
{
@@ -184,11 +168,7 @@ enum AtLastRites
class AreaTrigger_at_last_rites : public AreaTriggerScript
{
public:
-
- AreaTrigger_at_last_rites()
- : AreaTriggerScript("at_last_rites")
- {
- }
+ AreaTrigger_at_last_rites() : AreaTriggerScript("at_last_rites") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) override
{
@@ -246,7 +226,6 @@ enum Waygate
class AreaTrigger_at_sholazar_waygate : public AreaTriggerScript
{
public:
-
AreaTrigger_at_sholazar_waygate() : AreaTriggerScript("at_sholazar_waygate") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) override
diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp
index ca00b0fc352..4bb88a560bb 100644
--- a/src/server/scripts/World/go_scripts.cpp
+++ b/src/server/scripts/World/go_scripts.cpp
@@ -118,7 +118,8 @@ public:
enum GildedBrazier
{
- NPC_STILLBLADE = 17716,
+ NPC_STILLBLADE = 17716,
+ QUEST_THE_FIRST_TRIAL = 9678
};
class go_gilded_brazier : public GameObjectScript
@@ -130,7 +131,7 @@ public:
{
if (go->GetGoType() == GAMEOBJECT_TYPE_GOOBER)
{
- if (player->GetQuestStatus(9678) == QUEST_STATUS_INCOMPLETE)
+ if (player->GetQuestStatus(QUEST_THE_FIRST_TRIAL) == QUEST_STATUS_INCOMPLETE)
{
if (Creature* Stillblade = player->SummonCreature(NPC_STILLBLADE, 8106.11f, -7542.06f, 151.775f, 3.02598f, TEMPSUMMON_DEAD_DESPAWN, 60000))
Stillblade->AI()->AttackStart(player);
diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp
index 21a81d37868..a156a41fcef 100644
--- a/src/server/scripts/World/guards.cpp
+++ b/src/server/scripts/World/guards.cpp
@@ -387,7 +387,7 @@ public:
void AddSC_guards()
{
- new guard_generic;
- new guard_shattrath_aldor;
- new guard_shattrath_scryer;
+ new guard_generic();
+ new guard_shattrath_aldor();
+ new guard_shattrath_scryer();
}
diff --git a/src/server/scripts/World/mob_generic_creature.cpp b/src/server/scripts/World/mob_generic_creature.cpp
index 30666d5d2ea..2eb91b7b8fe 100644
--- a/src/server/scripts/World/mob_generic_creature.cpp
+++ b/src/server/scripts/World/mob_generic_creature.cpp
@@ -229,6 +229,6 @@ public:
void AddSC_generic_creature()
{
//new generic_creature;
- new trigger_periodic;
+ new trigger_periodic();
//new trigger_death;
}
diff --git a/src/server/scripts/World/npc_innkeeper.cpp b/src/server/scripts/World/npc_innkeeper.cpp
index b647cccf8ea..be56e57cc9d 100644
--- a/src/server/scripts/World/npc_innkeeper.cpp
+++ b/src/server/scripts/World/npc_innkeeper.cpp
@@ -134,6 +134,6 @@ public:
void AddSC_npc_innkeeper()
{
- new npc_innkeeper;
+ new npc_innkeeper();
}
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index c32edff09bc..e67823a2939 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -185,7 +185,6 @@ public:
}
void MoveInLineOfSight(Unit* who) override
-
{
if (!SpawnAssoc)
return;
@@ -1520,7 +1519,10 @@ class npc_brewfest_reveler : public CreatureScript
enum TrainingDummy
{
NPC_ADVANCED_TARGET_DUMMY = 2674,
- NPC_TARGET_DUMMY = 2673
+ NPC_TARGET_DUMMY = 2673,
+
+ EVENT_TD_CHECK_COMBAT = 1,
+ EVENT_TD_DESPAWN = 2
};
class npc_training_dummy : public CreatureScript
@@ -1533,20 +1535,22 @@ public:
npc_training_dummyAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
- entry = creature->GetEntry();
}
- uint32 entry;
- uint32 resetTimer;
- uint32 despawnTimer;
+ EventMap _events;
+ std::unordered_map<uint64, time_t> _damageTimes;
void Reset() override
{
me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);//imune to knock aways like blast wave
- resetTimer = 5000;
- despawnTimer = 15000;
+ _events.Reset();
+ _damageTimes.clear();
+ if (me->GetEntry() != NPC_ADVANCED_TARGET_DUMMY && me->GetEntry() != NPC_TARGET_DUMMY)
+ _events.ScheduleEvent(EVENT_TD_CHECK_COMBAT, 1000);
+ else
+ _events.ScheduleEvent(EVENT_TD_DESPAWN, 15000);
}
void EnterEvadeMode() override
@@ -1557,37 +1561,52 @@ public:
Reset();
}
- void DamageTaken(Unit* /*doneBy*/, uint32& damage) override
+ void DamageTaken(Unit* doneBy, uint32& damage) override
{
- resetTimer = 5000;
+ me->AddThreat(doneBy, float(damage)); // just to create threat reference
+ _damageTimes[doneBy->GetGUID()] = time(NULL);
damage = 0;
}
void UpdateAI(uint32 diff) override
{
- if (!UpdateVictim())
+ if (!me->IsInCombat())
return;
if (!me->HasUnitState(UNIT_STATE_STUNNED))
me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate
- if (entry != NPC_ADVANCED_TARGET_DUMMY && entry != NPC_TARGET_DUMMY)
+ _events.Update(diff);
+
+ if (uint32 eventId = _events.ExecuteEvent())
{
- if (resetTimer <= diff)
+ switch (eventId)
{
- EnterEvadeMode();
- resetTimer = 5000;
+ case EVENT_TD_CHECK_COMBAT:
+ {
+ time_t now = time(NULL);
+ for (std::unordered_map<uint64, time_t>::iterator itr = _damageTimes.begin(); itr != _damageTimes.end();)
+ {
+ // If unit has not dealt damage to training dummy for 5 seconds, remove him from combat
+ if (itr->second < now - 5)
+ {
+ if (Unit* unit = ObjectAccessor::GetUnit(*me, itr->first))
+ unit->getHostileRefManager().deleteReference(me);
+
+ itr = _damageTimes.erase(itr);
+ }
+ else
+ ++itr;
+ }
+ _events.ScheduleEvent(EVENT_TD_CHECK_COMBAT, 1000);
+ break;
+ }
+ case EVENT_TD_DESPAWN:
+ me->DespawnOrUnsummon(1);
+ break;
+ default:
+ break;
}
- else
- resetTimer -= diff;
- return;
- }
- else
- {
- if (despawnTimer <= diff)
- me->DespawnOrUnsummon();
- else
- despawnTimer -= diff;
}
}
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp
index de1e5b992e6..488ff18dca4 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp
@@ -69,6 +69,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_UPD_MUTE_TIME, "UPDATE account SET mutetime = ? , mutereason = ? , muteby = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_UPD_LAST_ATTEMPT_IP, "UPDATE account SET last_attempt_ip = ? WHERE username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = 1 WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_UPTIME_PLAYERS, "UPDATE uptime SET uptime = ?, maxplayers = ? WHERE realmid = ? AND starttime = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_OLD_LOGS, "DELETE FROM logs WHERE (time + ?) < ?", CONNECTION_ASYNC);
@@ -90,12 +91,21 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_ACCOUNT_RECRUITER, "SELECT 1 FROM account WHERE recruiter = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_BANS, "SELECT 1 FROM account_banned WHERE id = ? AND active = 1 UNION SELECT 1 FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_LAST_ATTEMPT_IP, "SELECT last_attempt_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_LAST_IP, "SELECT last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP2NATION_COUNTRY, "SELECT c.country FROM ip2nationCountries c, ip2nation i WHERE i.ip < ? AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_GET_EMAIL_BY_ID, "SELECT email FROM account WHERE id = ?", CONNECTION_SYNCH);
-
+ // 0: uint32, 1: uint32, 2: uint8, 3: uint32, 4: string // Complete name: "Login_Insert_AccountLoginDeLete_IP_Logging"
+ PrepareStatement(LOGIN_INS_ALDL_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, (SELECT last_ip FROM account WHERE id = ?), ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: uint32, 1: uint32, 2: uint8, 3: uint32, 4: string // Complete name: "Login_Insert_FailedAccountLogin_IP_Logging"
+ PrepareStatement(LOGIN_INS_FACL_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, (SELECT last_attempt_ip FROM account WHERE id = ?), ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: uint32, 1: uint32, 2: uint8, 3: string, 4: string // Complete name: "Login_Insert_CharacterDelete_IP_Logging"
+ PrepareStatement(LOGIN_INS_CHAR_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: string, 1: string, 2: string // Complete name: "Login_Insert_Failed_Account_Login_due_password_IP_Logging"
+ PrepareStatement(LOGIN_INS_FALP_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES ((SELECT id FROM account WHERE username = ?), 0, 1, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH);
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h
index 01f9fd973b6..604e9d39551 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.h
+++ b/src/server/shared/Database/Implementation/LoginDatabase.h
@@ -89,6 +89,7 @@ enum LoginDatabaseStatements
LOGIN_UPD_MUTE_TIME,
LOGIN_UPD_MUTE_TIME_LOGIN,
LOGIN_UPD_LAST_IP,
+ LOGIN_UPD_LAST_ATTEMPT_IP,
LOGIN_UPD_ACCOUNT_ONLINE,
LOGIN_UPD_UPTIME_PLAYERS,
LOGIN_DEL_OLD_LOGS,
@@ -114,7 +115,13 @@ enum LoginDatabaseStatements
LOGIN_DEL_ACCOUNT,
LOGIN_SEL_IP2NATION_COUNTRY,
LOGIN_SEL_AUTOBROADCAST,
+ LOGIN_SEL_LAST_ATTEMPT_IP,
+ LOGIN_SEL_LAST_IP,
LOGIN_GET_EMAIL_BY_ID,
+ LOGIN_INS_ALDL_IP_LOGGING,
+ LOGIN_INS_FACL_IP_LOGGING,
+ LOGIN_INS_CHAR_IP_LOGGING,
+ LOGIN_INS_FALP_IP_LOGGING,
LOGIN_SEL_ACCOUNT_ACCESS_BY_ID,
LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS,
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp
index 81825c9055b..350a258f455 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.cpp
+++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp
@@ -60,6 +60,7 @@ HANDLE WheatyExceptionReport::m_hReportFile;
HANDLE WheatyExceptionReport::m_hDumpFile;
HANDLE WheatyExceptionReport::m_hProcess;
SymbolPairs WheatyExceptionReport::symbols;
+std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails;
// Declare global instance of class
WheatyExceptionReport g_WheatyExceptionReport;
@@ -767,18 +768,21 @@ ULONG /*SymbolSize*/,
PVOID UserContext)
{
- char szBuffer[1024 * 64];
+ char szBuffer[WER_LARGE_BUFFER_SIZE];
+ memset(szBuffer, 0, sizeof(szBuffer));
__try
{
ClearSymbols();
if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext,
szBuffer, sizeof(szBuffer)))
- _tprintf(_T("\t%s\r\n"), szBuffer);
+ _tprintf(_T("%s"), szBuffer);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
- _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name);
+ _tprintf(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name);
+ if (szBuffer[0] != '\0')
+ _tprintf(_T("%s"), szBuffer);
}
return TRUE;
@@ -797,12 +801,6 @@ unsigned /*cbBuffer*/)
{
char * pszCurrBuffer = pszBuffer;
- // Indicate if the variable is a local or parameter
- if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
- pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter ");
- else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
- pszCurrBuffer += sprintf(pszCurrBuffer, "Local ");
-
// If it's a function, don't do anything.
if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK
return false;
@@ -824,19 +822,25 @@ unsigned /*cbBuffer*/)
// return false;
}
else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
- {
return false; // Don't try to report register variable
- }
else
{
pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable
}
+ pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
+
+ // Indicate if the variable is a local or parameter
+ if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
+ symbolDetails.top().Prefix = "Parameter ";
+ else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
+ symbolDetails.top().Prefix = "Local ";
+
// Determine if the variable is a user defined type (UDT). IF so, bHandled
// will return true.
bool bHandled;
pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex,
- 0, pVariable, bHandled, pSym->Name, "");
+ 0, pVariable, bHandled, pSym->Name, "", false, true);
if (!bHandled)
{
@@ -844,15 +848,19 @@ unsigned /*cbBuffer*/)
// variable. Based on the size, we're assuming it's a char, WORD, or
// DWORD.
BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase);
- pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
// Emit the variable name
- pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name);
+ if (pSym->Name[0] != '\0')
+ symbolDetails.top().Name = pSym->Name;
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size,
- (PVOID)pVariable);
+ char buffer[50];
+ FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
}
+ pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
return true;
}
@@ -868,13 +876,15 @@ DWORD dwTypeIndex,
unsigned nestingLevel,
DWORD_PTR offset,
bool & bHandled,
-char* Name,
-char* suffix)
+const char* Name,
+char* /*suffix*/,
+bool newSymbol,
+bool logChildren)
{
bHandled = false;
- if (!StoreSymbol(dwTypeIndex, offset))
- return pszCurrBuffer;
+ if (newSymbol)
+ pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
DWORD typeTag;
if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
@@ -890,19 +900,39 @@ char* suffix)
if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0)
{
LocalFree(pwszTypeName);
- pszCurrBuffer += sprintf(pszCurrBuffer, " %s", "std::string");
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, btStdString, 0, (PVOID)offset);
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
+ symbolDetails.top().Type = "std::string";
+ char buffer[50];
+ FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
+ if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
bHandled = true;
return pszCurrBuffer;
}
- pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName);
+ char buffer[200];
+ wcstombs(buffer, pwszTypeName, sizeof(buffer));
+ buffer[199] = '\0';
+ if (Name != NULL && Name[0] != '\0')
+ {
+ symbolDetails.top().Type = buffer;
+ symbolDetails.top().Name = Name;
+ }
+ else if (buffer[0] != '\0')
+ symbolDetails.top().Name = buffer;
+
LocalFree(pwszTypeName);
}
+ else if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
- if (strlen(suffix) > 0)
- pszCurrBuffer += sprintf(pszCurrBuffer, "%s", suffix);
+ if (!StoreSymbol(dwTypeIndex, offset))
+ {
+ // Skip printing address and base class if it has been printed already
+ if (typeTag == SymTagBaseClass)
+ bHandled = true;
+ return pszCurrBuffer;
+ }
DWORD innerTypeID;
switch (typeTag)
@@ -910,11 +940,9 @@ char* suffix)
case SymTagPointerType:
if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
{
-#define MAX_NESTING_LEVEL 5
- if (nestingLevel >= MAX_NESTING_LEVEL)
- break;
+ if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
- pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name);
BOOL isReference;
SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
@@ -922,44 +950,56 @@ char* suffix)
memset(addressStr, 0, sizeof(addressStr));
if (isReference)
- addressStr[0] = '&';
+ symbolDetails.top().Suffix += "&";
else
- addressStr[0] = '*';
+ symbolDetails.top().Suffix += "*";
- DWORD_PTR address = *(PDWORD_PTR)offset;
- if (address == NULL)
- {
- pwszTypeName;
- if (SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMNAME,
- &pwszTypeName))
- {
- pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName);
- LocalFree(pwszTypeName);
- }
+ // Try to dereference the pointer in a try/except block since it might be invalid
+ DWORD_PTR address = DereferenceUnsafePointer(offset);
- pszCurrBuffer += sprintf(pszCurrBuffer, "%s = NULL\r\n", addressStr);
+ char buffer[50];
+ FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
- bHandled = true;
- return pszCurrBuffer;
- }
- else
- {
- FormatOutputValue(&addressStr[1], btVoid, sizeof(PVOID), (PVOID)offset);
- pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
- address, bHandled, "", addressStr);
+ if (nestingLevel >= WER_MAX_NESTING_LEVEL)
+ logChildren = false;
+
+ // no need to log any children since the address is invalid anyway
+ if (address == NULL || address == DWORD_PTR(-1))
+ logChildren = false;
+
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ address, bHandled, Name, addressStr, false, logChildren);
- if (!bHandled)
+ if (!bHandled)
+ {
+ BasicType basicType = GetBasicType(dwTypeIndex, modBase);
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
+
+ if (address == NULL)
+ symbolDetails.top().Value = "NULL";
+ else if (address == DWORD_PTR(-1))
+ symbolDetails.top().Value = "<Unable to read memory>";
+ else
{
- BasicType basicType = GetBasicType(dwTypeIndex, modBase);
- pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
// Get the size of the child member
ULONG64 length;
SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, length, (PVOID)address);
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
- bHandled = true;
- return pszCurrBuffer;
+ char buffer[50];
+ FormatOutputValue(buffer, basicType, length, (PVOID)address, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
}
+ bHandled = true;
+ return pszCurrBuffer;
+ }
+ else if (address == NULL)
+ symbolDetails.top().Value = "NULL";
+ else if (address == DWORD_PTR(-1))
+ {
+ symbolDetails.top().Value = "<Unable to read memory>";
+ bHandled = true;
+ return pszCurrBuffer;
}
}
break;
@@ -970,13 +1010,80 @@ char* suffix)
if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
break;
- if (innerTypeTag == SymTagPointerType)
+ switch (innerTypeTag)
{
- pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name);
+ case SymTagUDT:
+ if (nestingLevel >= WER_MAX_NESTING_LEVEL)
+ logChildren = false;
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
+ break;
+ case SymTagPointerType:
+ if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
+ break;
+ case SymTagArrayType:
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case SymTagArrayType:
+ if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
+ {
+ symbolDetails.top().HasChildren = true;
+
+ BasicType basicType = btNoType;
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, Name, "", false, false);
+
+ // Set Value back to an empty string since the Array object itself has no value, only its elements have
+ symbolDetails.top().Value = "";
+
+ DWORD elementsCount;
+ if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
+ symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]";
+ else
+ symbolDetails.top().Suffix += "[<unknown count>]";
- pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
- offset, bHandled, "", "");
+ if (!bHandled)
+ {
+ basicType = GetBasicType(dwTypeIndex, modBase);
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
+ bHandled = true;
+ }
+
+ // Get the size of the child member
+ ULONG64 length;
+ SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
+
+ char buffer[50];
+ switch (basicType)
+ {
+ case btChar:
+ case btStdString:
+ FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
+ break;
+ default:
+ for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++)
+ {
+ pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
+ symbolDetails.top().Suffix += "[" + std::to_string(index) + "]";
+ FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer));
+ symbolDetails.top().Value = buffer;
+ pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
+ }
+ break;
}
+
+ return pszCurrBuffer;
}
break;
case SymTagBaseType:
@@ -1013,26 +1120,37 @@ char* suffix)
return pszCurrBuffer;
}
- // Append a line feed
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
-
// Iterate through each of the children
for (unsigned i = 0; i < dwChildrenCount; i++)
{
DWORD symTag;
SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag);
- if (symTag == SymTagFunction || symTag == SymTagTypedef)
+ if (symTag == SymTagFunction ||
+ symTag == SymTagEnum ||
+ symTag == SymTagTypedef ||
+ symTag == SymTagVTable)
continue;
- // Add appropriate indentation level (since this routine is recursive)
- for (unsigned j = 0; j <= nestingLevel+1; j++)
- pszCurrBuffer += sprintf(pszCurrBuffer, "\t");
+ // Ignore static fields
+ DWORD dataKind;
+ SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind);
+ if (dataKind == DataIsStaticLocal ||
+ dataKind == DataIsGlobal ||
+ dataKind == DataIsStaticMember)
+ continue;
+
+
+ symbolDetails.top().HasChildren = true;
+ if (!logChildren)
+ {
+ bHandled = false;
+ return pszCurrBuffer;
+ }
// Recurse for each of the child types
bool bHandled2;
BasicType basicType = GetBasicType(children.ChildId[i], modBase);
- pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
// Get the offset of the child member, relative to its parent
DWORD dwMemberOffset;
@@ -1044,11 +1162,14 @@ char* suffix)
pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase,
children.ChildId[i], nestingLevel+1,
- dwFinalOffset, bHandled2, ""/*Name */, "");
+ dwFinalOffset, bHandled2, ""/*Name */, "", true, true);
// If the child wasn't a UDT, format it appropriately
if (!bHandled2)
{
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
+
// Get the real "TypeId" of the child. We need this for the
// SymGetTypeInfo(TI_GET_TYPEID) call below.
DWORD typeId;
@@ -1059,75 +1180,75 @@ char* suffix)
ULONG64 length;
SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length);
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType,
- length, (PVOID)dwFinalOffset);
-
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
+ char buffer[50];
+ FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
}
+
+ pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
}
bHandled = true;
return pszCurrBuffer;
}
-char * WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer,
+void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer,
BasicType basicType,
DWORD64 length,
-PVOID pAddress)
+PVOID pAddress,
+size_t bufferSize)
{
__try
{
switch (basicType)
{
case btChar:
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", pAddress);
+ {
+ if (strlen((char*)pAddress) > bufferSize - 6)
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, (char*)pAddress);
+ else
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", (char*)pAddress);
break;
+ }
case btStdString:
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", static_cast<std::string*>(pAddress)->c_str());
+ {
+ std::string* value = static_cast<std::string*>(pAddress);
+ if (value->length() > bufferSize - 6)
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, value->c_str());
+ else
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str());
break;
+ }
default:
// Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
if (length == 1)
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress);
else if (length == 2)
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress);
else if (length == 4)
{
if (basicType == btFloat)
- {
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %f", *(PFLOAT)pAddress);
- }
- else if (basicType == btChar)
- {
- if (!IsBadStringPtr(*(PSTR*)pAddress, 32))
- {
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"",
- *(PSTR*)pAddress);
- }
- else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X",
- *(PDWORD)pAddress);
- }
+ pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress);
else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PDWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress);
}
else if (length == 8)
{
if (basicType == btFloat)
{
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf",
+ pszCurrBuffer += sprintf(pszCurrBuffer, "%lf",
*(double *)pAddress);
}
else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X",
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X",
*(DWORD64*)pAddress);
}
else
{
#if _WIN64
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", (DWORD64*)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", (DWORD64*)pAddress);
#else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", (PDWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", (PDWORD)pAddress);
#endif
}
break;
@@ -1136,13 +1257,11 @@ PVOID pAddress)
__except (EXCEPTION_EXECUTE_HANDLER)
{
#if _WIN64
- pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %I64X", (DWORD64*)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X <Unable to read memory>", (DWORD64*)pAddress);
#else
- pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %X", (PDWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X <Unable to read memory>", (PDWORD)pAddress);
#endif
}
-
- return pszCurrBuffer;
}
BasicType
@@ -1170,13 +1289,25 @@ WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase)
return btNoType;
}
+DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address)
+{
+ __try
+ {
+ return *(PDWORD_PTR)address;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return DWORD_PTR(-1);
+ }
+}
+
//============================================================================
// Helper function that writes to the report file, and allows the user to use
// printf style formating
//============================================================================
int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...)
{
- TCHAR szBuff[1024 * 64];
+ TCHAR szBuff[WER_LARGE_BUFFER_SIZE];
int retValue;
DWORD cbWritten;
va_list argptr;
@@ -1198,6 +1329,41 @@ bool WheatyExceptionReport::StoreSymbol(DWORD type, DWORD_PTR offset)
void WheatyExceptionReport::ClearSymbols()
{
symbols.clear();
+ while (!symbolDetails.empty())
+ symbolDetails.pop();
+}
+
+char* WheatyExceptionReport::PushSymbolDetail(char* pszCurrBuffer)
+{
+ // Log current symbol and then add another to the stack to keep the hierarchy format
+ pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer);
+ symbolDetails.emplace();
+ return pszCurrBuffer;
+}
+
+char* WheatyExceptionReport::PopSymbolDetail(char* pszCurrBuffer)
+{
+ pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer);
+ symbolDetails.pop();
+ return pszCurrBuffer;
+}
+
+char* WheatyExceptionReport::PrintSymbolDetail(char* pszCurrBuffer)
+{
+ if (symbolDetails.empty())
+ return pszCurrBuffer;
+
+ // Don't log anything if has been logged already or if it's empty
+ if (symbolDetails.top().Logged || symbolDetails.top().empty())
+ return pszCurrBuffer;
+
+ // Add appropriate indentation level (since this routine is recursive)
+ for (size_t i = 0; i < symbolDetails.size(); i++)
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\t");
+
+ pszCurrBuffer += sprintf(pszCurrBuffer, "%s\r\n", symbolDetails.top().ToString().c_str());
+
+ return pszCurrBuffer;
}
#endif // _WIN32
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h
index e1cc3050929..9137b91aac9 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.h
+++ b/src/server/shared/Debugging/WheatyExceptionReport.h
@@ -5,12 +5,13 @@
#include <dbghelp.h>
#include <set>
-#if _MSC_VER < 1400
-# define countof(array) (sizeof(array) / sizeof(array[0]))
-#else
-# include <stdlib.h>
-# define countof _countof
-#endif // _MSC_VER < 1400
+#include <stdlib.h>
+#include <stack>
+#define countof _countof
+
+#define WER_MAX_ARRAY_ELEMENTS_COUNT 10
+#define WER_MAX_NESTING_LEVEL 5
+#define WER_LARGE_BUFFER_SIZE 1024 * 128
enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK
{
@@ -37,40 +38,54 @@ enum BasicType // Stolen from CVCON
btStdString = 101
};
+enum DataKind // Stolen from CVCONST.H in the DIA 2.0 SDK
+{
+ DataIsUnknown,
+ DataIsLocal,
+ DataIsStaticLocal,
+ DataIsParam,
+ DataIsObjectPtr,
+ DataIsFileStatic,
+ DataIsGlobal,
+ DataIsMember,
+ DataIsStaticMember,
+ DataIsConstant
+};
+
const char* const rgBaseType[] =
{
- " <user defined> ", // btNoType = 0,
- " void ", // btVoid = 1,
- " char* ", // btChar = 2,
- " wchar_t* ", // btWChar = 3,
- " signed char ",
- " unsigned char ",
- " int ", // btInt = 6,
- " unsigned int ", // btUInt = 7,
- " float ", // btFloat = 8,
- " <BCD> ", // btBCD = 9,
- " bool ", // btBool = 10,
- " short ",
- " unsigned short ",
- " long ", // btLong = 13,
- " unsigned long ", // btULong = 14,
- " __int8 ",
- " __int16 ",
- " __int32 ",
- " __int64 ",
- " __int128 ",
- " unsigned __int8 ",
- " unsigned __int16 ",
- " unsigned __int32 ",
- " unsigned __int64 ",
- " unsigned __int128 ",
- " <currency> ", // btCurrency = 25,
- " <date> ", // btDate = 26,
- " VARIANT ", // btVariant = 27,
- " <complex> ", // btComplex = 28,
- " <bit> ", // btBit = 29,
- " BSTR ", // btBSTR = 30,
- " HRESULT " // btHresult = 31
+ "<user defined>", // btNoType = 0,
+ "void", // btVoid = 1,
+ "char",//char* // btChar = 2,
+ "wchar_t*", // btWChar = 3,
+ "signed char",
+ "unsigned char",
+ "int", // btInt = 6,
+ "unsigned int", // btUInt = 7,
+ "float", // btFloat = 8,
+ "<BCD>", // btBCD = 9,
+ "bool", // btBool = 10,
+ "short",
+ "unsigned short",
+ "long", // btLong = 13,
+ "unsigned long", // btULong = 14,
+ "int8",
+ "int16",
+ "int32",
+ "int64",
+ "int128",
+ "uint8",
+ "uint16",
+ "uint32",
+ "uint64",
+ "uint128",
+ "<currency>", // btCurrency = 25,
+ "<date>", // btDate = 26,
+ "VARIANT", // btVariant = 27,
+ "<complex>", // btComplex = 28,
+ "<bit>", // btBit = 29,
+ "BSTR", // btBSTR = 30,
+ "HRESULT" // btHresult = 31
};
struct SymbolPair
@@ -92,6 +107,39 @@ struct SymbolPair
};
typedef std::set<SymbolPair> SymbolPairs;
+struct SymbolDetail
+{
+ SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {}
+
+ std::string ToString()
+ {
+ Logged = true;
+ std::string formatted = Prefix + Type + Suffix;
+ if (!Name.empty())
+ {
+ if (!formatted.empty())
+ formatted += " ";
+ formatted += Name;
+ }
+ if (!Value.empty())
+ formatted += " = " + Value;
+ return formatted;
+ }
+
+ bool empty() const
+ {
+ return Value.empty() && !HasChildren;
+ }
+
+ std::string Prefix;
+ std::string Type;
+ std::string Suffix;
+ std::string Name;
+ std::string Value;
+ bool Logged;
+ bool HasChildren;
+};
+
class WheatyExceptionReport
{
public:
@@ -122,11 +170,12 @@ class WheatyExceptionReport
static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char * pszBuffer, unsigned cbBuffer);
- static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, char*, char*);
+ static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char*, char*, bool, bool);
- static char * FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress);
+ static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize);
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase);
+ static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address);
static int __cdecl _tprintf(const TCHAR * format, ...);
@@ -141,6 +190,12 @@ class WheatyExceptionReport
static HANDLE m_hDumpFile;
static HANDLE m_hProcess;
static SymbolPairs symbols;
+ static std::stack<SymbolDetail> symbolDetails;
+
+ static char* PushSymbolDetail(char* pszCurrBuffer);
+ static char* PopSymbolDetail(char* pszCurrBuffer);
+ static char* PrintSymbolDetail(char* pszCurrBuffer);
+
};
extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class
diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp
index ffef61557fc..28bbe831a69 100644
--- a/src/server/shared/Utilities/Util.cpp
+++ b/src/server/shared/Utilities/Util.cpp
@@ -547,3 +547,12 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse
return ss.str();
}
+
+uint32 EventMap::GetTimeUntilEvent(uint32 eventId) const
+{
+ for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
+ if (eventId == (itr->second & 0x0000FFFF))
+ return itr->first - _time;
+
+ return std::numeric_limits<uint32>::max();
+}
diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h
index d6ead607c55..648edf39abe 100644
--- a/src/server/shared/Utilities/Util.h
+++ b/src/server/shared/Utilities/Util.h
@@ -866,14 +866,7 @@ class EventMap
* @param Id of the event.
* @return Time of next event.
*/
- uint32 GetTimeUntilEvent(uint32 eventId) const
- {
- for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
- if (eventId == (itr->second & 0x0000FFFF))
- return itr->first - _time;
-
- return std::numeric_limits<uint32>::max();
- }
+ uint32 GetTimeUntilEvent(uint32 eventId) const;
private:
/**
diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt
index d1d2ef11848..78a29dbedf6 100644
--- a/src/server/worldserver/CMakeLists.txt
+++ b/src/server/worldserver/CMakeLists.txt
@@ -45,6 +45,7 @@ include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
${CMAKE_SOURCE_DIR}/dep/gsoap
${CMAKE_SOURCE_DIR}/dep/sockets/include
${CMAKE_SOURCE_DIR}/dep/SFMT
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index f71ef5d064b..90f330bac42 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1353,6 +1353,14 @@ Rate.Creature.Elite.RAREELITE.HP = 1
Rate.Creature.Elite.WORLDBOSS.HP = 1
#
+# Creature.PickPocketRefillDelay
+# Description: Time in seconds that the server will wait before refilling the pickpocket loot
+# for a creature
+# Default: 600
+
+Creature.PickPocketRefillDelay = 600
+
+#
# ListenRange.Say
# Description: Distance in which players can read say messages from creatures or
# gameobjects.
@@ -2735,6 +2743,13 @@ Logger.sql.sql=5,Console DBErrors
Log.Async.Enable = 0
#
+# Allow.IP.Based.Action.Logging
+# Description: Logs actions, e.g. account login and logout to name a few, based on IP of current session.
+# Default: 0 - (Disabled)
+# 1 - (Enabled)
+
+Allow.IP.Based.Action.Logging = 0
+#
###################################################################################################
###################################################################################################
diff --git a/src/tools/mmaps_generator/CMakeLists.txt b/src/tools/mmaps_generator/CMakeLists.txt
index 591e0cc8e98..c0268680657 100644
--- a/src/tools/mmaps_generator/CMakeLists.txt
+++ b/src/tools/mmaps_generator/CMakeLists.txt
@@ -18,7 +18,9 @@ set(mmap_gen_Includes
${CMAKE_SOURCE_DIR}/dep/bzip2
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/game/Conditions
${CMAKE_SOURCE_DIR}/src/server/collision
diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp
index cc24035b05e..131041e0cd2 100644
--- a/src/tools/mmaps_generator/MapBuilder.cpp
+++ b/src/tools/mmaps_generator/MapBuilder.cpp
@@ -77,8 +77,8 @@ namespace MMAP
{
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
{
- (*it).second->clear();
- delete (*it).second;
+ (*it).m_tiles->clear();
+ delete (*it).m_tiles;
}
delete m_terrainBuilder;
@@ -97,9 +97,9 @@ namespace MMAP
for (uint32 i = 0; i < files.size(); ++i)
{
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
- if (m_tiles.find(mapID) == m_tiles.end())
+ if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end())
{
- m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>));
+ m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>));
count++;
}
}
@@ -109,8 +109,11 @@ namespace MMAP
for (uint32 i = 0; i < files.size(); ++i)
{
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
- m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>));
- count++;
+ if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end())
+ {
+ m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>));
+ count++;
+ }
}
printf("found %u.\n", count);
@@ -118,8 +121,8 @@ namespace MMAP
printf("Discovering tiles... ");
for (TileList::iterator itr = m_tiles.begin(); itr != m_tiles.end(); ++itr)
{
- std::set<uint32>* tiles = (*itr).second;
- mapID = (*itr).first;
+ std::set<uint32>* tiles = (*itr).m_tiles;
+ mapID = (*itr).m_mapId;
sprintf(filter, "%03u*.vmtile", mapID);
files.clear();
@@ -153,12 +156,12 @@ namespace MMAP
/**************************************************************************/
std::set<uint32>* MapBuilder::getTileList(uint32 mapID)
{
- TileList::iterator itr = m_tiles.find(mapID);
+ TileList::iterator itr = std::find(m_tiles.begin(), m_tiles.end(), mapID);
if (itr != m_tiles.end())
- return (*itr).second;
+ return (*itr).m_tiles;
std::set<uint32>* tiles = new std::set<uint32>();
- m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, tiles));
+ m_tiles.emplace_back(MapTiles(mapID, tiles));
return tiles;
}
@@ -169,9 +172,14 @@ namespace MMAP
BuilderThreadPool* pool = threads > 0 ? new BuilderThreadPool() : NULL;
+ m_tiles.sort([](MapTiles a, MapTiles b)
+ {
+ return a.m_tiles->size() > b.m_tiles->size();
+ });
+
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
{
- uint32 mapID = it->first;
+ uint32 mapID = it->m_mapId;
if (!shouldSkipMap(mapID))
{
if (threads > 0)
diff --git a/src/tools/mmaps_generator/MapBuilder.h b/src/tools/mmaps_generator/MapBuilder.h
index 86a6db2077c..08b87324d01 100644
--- a/src/tools/mmaps_generator/MapBuilder.h
+++ b/src/tools/mmaps_generator/MapBuilder.h
@@ -22,6 +22,7 @@
#include <vector>
#include <set>
#include <map>
+#include <list>
#include "TerrainBuilder.h"
#include "IntermediateValues.h"
@@ -39,7 +40,24 @@ using namespace VMAP;
namespace MMAP
{
- typedef std::map<uint32, std::set<uint32>*> TileList;
+ struct MapTiles
+ {
+ MapTiles() : m_mapId(uint32(-1)), m_tiles(NULL) {}
+
+ MapTiles(uint32 id, std::set<uint32>* tiles) : m_mapId(id), m_tiles(tiles) {}
+ ~MapTiles() {}
+
+ uint32 m_mapId;
+ std::set<uint32>* m_tiles;
+
+ bool operator==(uint32 id)
+ {
+ return m_mapId == id;
+ }
+ };
+
+ typedef std::list<MapTiles> TileList;
+
struct Tile
{
Tile() : chf(NULL), solid(NULL), cset(NULL), pmesh(NULL), dmesh(NULL) {}