Many, many cmangos Cata commits applied

The following commits were either applied or found not to be applicable:
This commit is contained in:
Charles A Edwards 2016-08-27 18:42:03 +01:00 committed by Antz
parent 32a26f44c7
commit a800f3b1ad
100 changed files with 2385 additions and 1305 deletions

View file

@ -213,32 +213,32 @@ BattleGround::BattleGround()
m_MapId = 0; m_MapId = 0;
m_Map = NULL; m_Map = NULL;
m_TeamStartLocX[BG_TEAM_ALLIANCE] = 0; m_TeamStartLocX[TEAM_INDEX_ALLIANCE] = 0;
m_TeamStartLocX[BG_TEAM_HORDE] = 0; m_TeamStartLocX[TEAM_INDEX_HORDE] = 0;
m_TeamStartLocY[BG_TEAM_ALLIANCE] = 0; m_TeamStartLocY[TEAM_INDEX_ALLIANCE] = 0;
m_TeamStartLocY[BG_TEAM_HORDE] = 0; m_TeamStartLocY[TEAM_INDEX_HORDE] = 0;
m_TeamStartLocZ[BG_TEAM_ALLIANCE] = 0; m_TeamStartLocZ[TEAM_INDEX_ALLIANCE] = 0;
m_TeamStartLocZ[BG_TEAM_HORDE] = 0; m_TeamStartLocZ[TEAM_INDEX_HORDE] = 0;
m_TeamStartLocO[BG_TEAM_ALLIANCE] = 0; m_TeamStartLocO[TEAM_INDEX_ALLIANCE] = 0;
m_TeamStartLocO[BG_TEAM_HORDE] = 0; m_TeamStartLocO[TEAM_INDEX_HORDE] = 0;
m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0; m_ArenaTeamIds[TEAM_INDEX_ALLIANCE] = 0;
m_ArenaTeamIds[BG_TEAM_HORDE] = 0; m_ArenaTeamIds[TEAM_INDEX_HORDE] = 0;
m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0; m_ArenaTeamRatingChanges[TEAM_INDEX_ALLIANCE] = 0;
m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0; m_ArenaTeamRatingChanges[TEAM_INDEX_HORDE] = 0;
m_BgRaids[BG_TEAM_ALLIANCE] = NULL; m_BgRaids[TEAM_INDEX_ALLIANCE] = NULL;
m_BgRaids[BG_TEAM_HORDE] = NULL; m_BgRaids[TEAM_INDEX_HORDE] = NULL;
m_PlayersCount[BG_TEAM_ALLIANCE] = 0; m_PlayersCount[TEAM_INDEX_ALLIANCE] = 0;
m_PlayersCount[BG_TEAM_HORDE] = 0; m_PlayersCount[TEAM_INDEX_HORDE] = 0;
m_TeamScores[BG_TEAM_ALLIANCE] = 0; m_TeamScores[TEAM_INDEX_ALLIANCE] = 0;
m_TeamScores[BG_TEAM_HORDE] = 0; m_TeamScores[TEAM_INDEX_HORDE] = 0;
m_PrematureCountDown = false; m_PrematureCountDown = false;
m_PrematureCountDownTimer = 0; m_PrematureCountDownTimer = 0;
@ -459,6 +459,14 @@ void BattleGround::Update(uint32 diff)
/*********************************************************/ /*********************************************************/
/*** BATTLEGROUND ENDING SYSTEM ***/ /*** BATTLEGROUND ENDING SYSTEM ***/
/*********************************************************/ /*********************************************************/
if (GetStatus() == STATUS_IN_PROGRESS && isArena())
{
// after 45 minutes without one team losing, the arena closes with no winner and -16 rating change for both
if (m_StartTime > uint32(m_StartDelayTimes[BG_STARTING_EVENT_FIRST] + ARENA_FORCED_DRAW))
{
EndBattleGround(TEAM_NONE);
}
}
if (GetStatus() == STATUS_WAIT_LEAVE) if (GetStatus() == STATUS_WAIT_LEAVE)
{ {
@ -485,7 +493,7 @@ void BattleGround::Update(uint32 diff)
void BattleGround::SetTeamStartLoc(Team team, float X, float Y, float Z, float O) void BattleGround::SetTeamStartLoc(Team team, float X, float Y, float Z, float O)
{ {
BattleGroundTeamIndex teamIdx = GetTeamIndexByTeamId(team); PvpTeamIndex teamIdx = GetTeamIndexByTeamId(team);
m_TeamStartLocX[teamIdx] = X; m_TeamStartLocX[teamIdx] = X;
m_TeamStartLocY[teamIdx] = Y; m_TeamStartLocY[teamIdx] = Y;
m_TeamStartLocZ[teamIdx] = Z; m_TeamStartLocZ[teamIdx] = Z;
@ -1322,18 +1330,20 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player* plr, ObjectGuid plr_gu
} }
// This method should be called when player logs into running battleground // This method should be called when player logs into running battleground
void BattleGround::EventPlayerLoggedIn(Player* player, ObjectGuid plr_guid) void BattleGround::EventPlayerLoggedIn(Player* player)
{ {
ObjectGuid playerGuid = player->GetObjectGuid();
// player is correct pointer // player is correct pointer
for (OfflineQueue::iterator itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr) for (OfflineQueue::iterator itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr)
{ {
if (*itr == plr_guid) if (*itr == playerGuid)
{ {
m_OfflineQueue.erase(itr); m_OfflineQueue.erase(itr);
break; break;
} }
} }
m_Players[plr_guid].OfflineRemoveTime = 0; m_Players[playerGuid].OfflineRemoveTime = 0;
PlayerAddedToBGCheckIfBGIsRunning(player); PlayerAddedToBGCheckIfBGIsRunning(player);
// if battleground is starting, then add preparation aura // if battleground is starting, then add preparation aura
// we don't have to do that, because preparation aura isn't removed when player logs out // we don't have to do that, because preparation aura isn't removed when player logs out
@ -1783,7 +1793,7 @@ WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard(Player* player)
bool BattleGround::IsTeamScoreInRange(Team team, uint32 minScore, uint32 maxScore) const bool BattleGround::IsTeamScoreInRange(Team team, uint32 minScore, uint32 maxScore) const
{ {
BattleGroundTeamIndex team_idx = GetTeamIndexByTeamId(team); PvpTeamIndex team_idx = GetTeamIndexByTeamId(team);
uint32 score = (m_TeamScores[team_idx] < 0) ? 0 : uint32(m_TeamScores[team_idx]); uint32 score = (m_TeamScores[team_idx] < 0) ? 0 : uint32(m_TeamScores[team_idx]);
return score >= minScore && score <= maxScore; return score >= minScore && score <= maxScore;
} }

View file

@ -112,13 +112,14 @@ enum BattleGroundTimeIntervals
{ {
RESURRECTION_INTERVAL = 30000, // ms RESURRECTION_INTERVAL = 30000, // ms
INVITATION_REMIND_TIME = 20000, // ms INVITATION_REMIND_TIME = 20000, // ms
INVITE_ACCEPT_WAIT_TIME = 40000, // ms INVITE_ACCEPT_WAIT_TIME = 60000, // ms
TIME_TO_AUTOREMOVE = 120000, // ms TIME_TO_AUTOREMOVE = 120000, // ms
MAX_OFFLINE_TIME = 300, // secs MAX_OFFLINE_TIME = 300, // secs
RESPAWN_ONE_DAY = 86400, // secs RESPAWN_ONE_DAY = 86400, // secs
RESPAWN_IMMEDIATELY = 0, // secs RESPAWN_IMMEDIATELY = 0, // secs
BUFF_RESPAWN_TIME = 180, // secs BUFF_RESPAWN_TIME = 180, // secs
ARENA_SPAWN_BUFF_OBJECTS = 90000, // ms - 90sec after start ARENA_SPAWN_BUFF_OBJECTS = 90000, // ms - 90sec after start
ARENA_FORCED_DRAW = 2700000, // ms - 45min after start
BATTLEGROUND_COUNTDOWN_MAX = 120, // secs BATTLEGROUND_COUNTDOWN_MAX = 120, // secs
ARENA_COUNTDOWN_MAX = 60, // secs ARENA_COUNTDOWN_MAX = 60, // secs
}; };
@ -212,14 +213,6 @@ enum BattleGroundType
TYPE_ARENA = 4 TYPE_ARENA = 4
}; };
enum BattleGroundTeamIndex
{
BG_TEAM_ALLIANCE = 0,
BG_TEAM_HORDE = 1
};
#define BG_TEAMS_COUNT 2
enum BattleGroundStartingEvents enum BattleGroundStartingEvents
{ {
BG_STARTING_EVENT_NONE = 0x00, BG_STARTING_EVENT_NONE = 0x00,
@ -432,7 +425,7 @@ class BattleGround
void SetTeamStartLoc(Team team, float X, float Y, float Z, float O); void SetTeamStartLoc(Team team, float X, float Y, float Z, float O);
void GetTeamStartLoc(Team team, float& X, float& Y, float& Z, float& O) const void GetTeamStartLoc(Team team, float& X, float& Y, float& Z, float& O) const
{ {
BattleGroundTeamIndex idx = GetTeamIndexByTeamId(team); PvpTeamIndex idx = GetTeamIndexByTeamId(team);
X = m_TeamStartLocX[idx]; X = m_TeamStartLocX[idx];
Y = m_TeamStartLocY[idx]; Y = m_TeamStartLocY[idx];
Z = m_TeamStartLocZ[idx]; Z = m_TeamStartLocZ[idx];
@ -477,7 +470,7 @@ class BattleGround
virtual void UpdatePlayerScore(Player* Source, uint32 type, uint32 value); virtual void UpdatePlayerScore(Player* Source, uint32 type, uint32 value);
static BattleGroundTeamIndex GetTeamIndexByTeamId(Team team) { return team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE; } static PvpTeamIndex GetTeamIndexByTeamId(Team team) { return team == ALLIANCE ? TEAM_INDEX_ALLIANCE : TEAM_INDEX_HORDE; }
uint32 GetPlayersCountByTeam(Team team) const { return m_PlayersCount[GetTeamIndexByTeamId(team)]; } uint32 GetPlayersCountByTeam(Team team) const { return m_PlayersCount[GetTeamIndexByTeamId(team)]; }
uint32 GetAlivePlayersCountByTeam(Team team) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases uint32 GetAlivePlayersCountByTeam(Team team) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases
void UpdatePlayersCountByTeam(Team team, bool remove) void UpdatePlayersCountByTeam(Team team, bool remove)
@ -518,7 +511,7 @@ class BattleGround
virtual void EventPlayerDroppedFlag(Player* /*player*/) {} virtual void EventPlayerDroppedFlag(Player* /*player*/) {}
virtual void EventPlayerClickedOnFlag(Player* /*player*/, GameObject* /*target_obj*/) {} virtual void EventPlayerClickedOnFlag(Player* /*player*/, GameObject* /*target_obj*/) {}
virtual void EventPlayerCapturedFlag(Player* /*player*/) {} virtual void EventPlayerCapturedFlag(Player* /*player*/) {}
void EventPlayerLoggedIn(Player* player, ObjectGuid plr_guid); void EventPlayerLoggedIn(Player* player);
void EventPlayerLoggedOut(Player* player); void EventPlayerLoggedOut(Player* player);
/* Death related */ /* Death related */
@ -563,11 +556,11 @@ class BattleGround
Team GetPlayerTeam(ObjectGuid guid); Team GetPlayerTeam(ObjectGuid guid);
uint32 GetRemainingTime() const { return m_EndTime; } uint32 GetRemainingTime() const { return m_EndTime; }
static Team GetOtherTeam(Team team) { return team ? ((team == ALLIANCE) ? HORDE : ALLIANCE) : TEAM_NONE; } static Team GetOtherTeam(Team team) { return team ? ((team == ALLIANCE) ? HORDE : ALLIANCE) : TEAM_NONE; }
static BattleGroundTeamIndex GetOtherTeamIndex(BattleGroundTeamIndex teamIdx) { return teamIdx == BG_TEAM_ALLIANCE ? BG_TEAM_HORDE : BG_TEAM_ALLIANCE; } static PvpTeamIndex GetOtherTeamIndex(PvpTeamIndex teamIdx) { return teamIdx == TEAM_INDEX_ALLIANCE ? TEAM_INDEX_HORDE : TEAM_INDEX_ALLIANCE; }
bool IsPlayerInBattleGround(ObjectGuid guid); bool IsPlayerInBattleGround(ObjectGuid guid);
/* virtual score-array - get's used in bg-subclasses */ /* virtual score-array - get's used in bg-subclasses */
int32 m_TeamScores[BG_TEAMS_COUNT]; int32 m_TeamScores[PVP_TEAM_COUNT];
struct EventObjects struct EventObjects
{ {
@ -640,15 +633,15 @@ class BattleGround
uint32 m_InvitedHorde; uint32 m_InvitedHorde;
/* Raid Group */ /* Raid Group */
Group* m_BgRaids[BG_TEAMS_COUNT]; // 0 - alliance, 1 - horde Group* m_BgRaids[PVP_TEAM_COUNT]; // 0 - alliance, 1 - horde
/* Players count by team */ /* Players count by team */
uint32 m_PlayersCount[BG_TEAMS_COUNT]; uint32 m_PlayersCount[PVP_TEAM_COUNT];
/* Arena team ids by team */ /* Arena team ids by team */
uint32 m_ArenaTeamIds[BG_TEAMS_COUNT]; uint32 m_ArenaTeamIds[PVP_TEAM_COUNT];
int32 m_ArenaTeamRatingChanges[BG_TEAMS_COUNT]; int32 m_ArenaTeamRatingChanges[PVP_TEAM_COUNT];
/* Limits */ /* Limits */
uint32 m_LevelMin; uint32 m_LevelMin;
@ -661,10 +654,10 @@ class BattleGround
/* Start location */ /* Start location */
uint32 m_MapId; uint32 m_MapId;
BattleGroundMap* m_Map; BattleGroundMap* m_Map;
float m_TeamStartLocX[BG_TEAMS_COUNT]; float m_TeamStartLocX[PVP_TEAM_COUNT];
float m_TeamStartLocY[BG_TEAMS_COUNT]; float m_TeamStartLocY[PVP_TEAM_COUNT];
float m_TeamStartLocZ[BG_TEAMS_COUNT]; float m_TeamStartLocZ[PVP_TEAM_COUNT];
float m_TeamStartLocO[BG_TEAMS_COUNT]; float m_TeamStartLocO[PVP_TEAM_COUNT];
}; };
// helper functions for world state list fill // helper functions for world state list fill

View file

@ -53,7 +53,7 @@ void BattleGroundAB::Update(uint32 diff)
if (GetStatus() == STATUS_IN_PROGRESS) if (GetStatus() == STATUS_IN_PROGRESS)
{ {
int team_points[BG_TEAMS_COUNT] = { 0, 0 }; int team_points[PVP_TEAM_COUNT] = { 0, 0 };
for (uint8 node = 0; node < BG_AB_NODES_MAX; ++node) for (uint8 node = 0; node < BG_AB_NODES_MAX; ++node)
{ {
@ -100,13 +100,13 @@ void BattleGroundAB::Update(uint32 diff)
} }
} }
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (uint8 team = 0; team < PVP_TEAM_COUNT; ++team)
if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED) if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED)
++team_points[team]; ++team_points[team];
} }
// Accumulate points // Accumulate points
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (uint8 team = 0; team < PVP_TEAM_COUNT; ++team)
{ {
int points = team_points[team]; int points = team_points[team];
if (!points) if (!points)
@ -120,17 +120,17 @@ void BattleGroundAB::Update(uint32 diff)
m_ReputationScoreTics[team] += BG_AB_TickPoints[points]; m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
if (m_ReputationScoreTics[team] >= m_ReputationTics) if (m_ReputationScoreTics[team] >= m_ReputationTics)
{ {
(team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE); (team == TEAM_INDEX_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE);
m_ReputationScoreTics[team] -= m_ReputationTics; m_ReputationScoreTics[team] -= m_ReputationTics;
} }
if (m_honorScoreTicks[team] >= m_honorTicks) if (m_honorScoreTicks[team] >= m_honorTicks)
{ {
RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE); RewardHonorToTeam(GetBonusHonorFromKill(1), (team == TEAM_INDEX_ALLIANCE) ? ALLIANCE : HORDE);
m_honorScoreTicks[team] -= m_honorTicks; m_honorScoreTicks[team] -= m_honorTicks;
} }
if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE) if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE)
{ {
if (team == BG_TEAM_ALLIANCE) if (team == TEAM_INDEX_ALLIANCE)
SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
else else
SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
@ -140,24 +140,24 @@ void BattleGroundAB::Update(uint32 diff)
if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE) if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE)
m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE; m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE;
if (team == BG_TEAM_ALLIANCE) if (team == TEAM_INDEX_ALLIANCE)
UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]); UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]);
if (team == BG_TEAM_HORDE) if (team == TEAM_INDEX_HORDE)
UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]); UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]);
// update achievement flags // update achievement flags
// we increased m_TeamScores[team] so we just need to check if it is 500 more than other teams resources // we increased m_TeamScores[team] so we just need to check if it is 500 more than other teams resources
// horde will be a bit disadvantaged, but we can assume that points aren't updated for both team in same Update() call // horde will be a bit disadvantaged, but we can assume that points aren't updated for both team in same Update() call
uint8 otherTeam = (team + 1) % BG_TEAMS_COUNT; uint8 otherTeam = (team + 1) % PVP_TEAM_COUNT;
if (m_TeamScores[team] > m_TeamScores[otherTeam] + 500) if (m_TeamScores[team] > m_TeamScores[otherTeam] + 500)
m_TeamScores500Disadvantage[otherTeam] = true; m_TeamScores500Disadvantage[otherTeam] = true;
} }
} }
// Test win condition // Test win condition
if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE) if (m_TeamScores[TEAM_INDEX_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE)
EndBattleGround(ALLIANCE); EndBattleGround(ALLIANCE);
if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE) if (m_TeamScores[TEAM_INDEX_HORDE] >= BG_AB_MAX_TEAM_SCORE)
EndBattleGround(HORDE); EndBattleGround(HORDE);
} }
} }
@ -277,8 +277,8 @@ void BattleGroundAB::FillInitialWorldStates(WorldPacket& data, uint32& count)
// Team scores // Team scores
FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_MAX, BG_AB_MAX_TEAM_SCORE); FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_MAX, BG_AB_MAX_TEAM_SCORE);
FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_WARNING, BG_AB_WARNING_NEAR_VICTORY_SCORE); FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_WARNING, BG_AB_WARNING_NEAR_VICTORY_SCORE);
FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_ALLY, m_TeamScores[BG_TEAM_ALLIANCE]); FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_ALLY, m_TeamScores[TEAM_INDEX_ALLIANCE]);
FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_HORDE, m_TeamScores[BG_TEAM_HORDE]); FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_HORDE, m_TeamScores[TEAM_INDEX_HORDE]);
// other unknown // other unknown
FillInitialWorldState(data, count, 0x745, 0x2); // 37 1861 unk FillInitialWorldState(data, count, 0x745, 0x2); // 37 1861 unk
@ -333,7 +333,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player* source, GameObject* target
return; return;
BG_AB_Nodes node = BG_AB_Nodes(event); BG_AB_Nodes node = BG_AB_Nodes(event);
BattleGroundTeamIndex teamIndex = GetTeamIndexByTeamId(source->GetTeam()); PvpTeamIndex teamIndex = GetTeamIndexByTeamId(source->GetTeam());
// Check if player really could use this banner, not cheated // Check if player really could use this banner, not cheated
if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node] % 2)) if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node] % 2))
@ -376,7 +376,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player* source, GameObject* target
_SendNodeUpdate(node); _SendNodeUpdate(node);
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
if (teamIndex == BG_TEAM_ALLIANCE) if (teamIndex == TEAM_INDEX_ALLIANCE)
SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED, CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED, CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
else else
SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED, CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED, CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
@ -391,14 +391,14 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player* source, GameObject* target
_CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true); _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
_SendNodeUpdate(node); _SendNodeUpdate(node);
m_NodeTimers[node] = 0; m_NodeTimers[node] = 0;
_NodeOccupied(node, (teamIndex == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE); _NodeOccupied(node, (teamIndex == TEAM_INDEX_ALLIANCE) ? ALLIANCE : HORDE);
if (teamIndex == BG_TEAM_ALLIANCE) if (teamIndex == TEAM_INDEX_ALLIANCE)
SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED, CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED, CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
else else
SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED, CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED, CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
} }
sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; sound = (teamIndex == TEAM_INDEX_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
} }
// If node is occupied, change to enemy-contested // If node is occupied, change to enemy-contested
else else
@ -411,18 +411,18 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player* source, GameObject* target
_SendNodeUpdate(node); _SendNodeUpdate(node);
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
if (teamIndex == BG_TEAM_ALLIANCE) if (teamIndex == TEAM_INDEX_ALLIANCE)
SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED, CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED, CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
else else
SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED, CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED, CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; sound = (teamIndex == TEAM_INDEX_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
} }
// If node is occupied again, send "X has taken the Y" msg. // If node is occupied again, send "X has taken the Y" msg.
if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED) if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED)
{ {
if (teamIndex == BG_TEAM_ALLIANCE) if (teamIndex == TEAM_INDEX_ALLIANCE)
SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_ALLY, _GetNodeNameId(node)); SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_ALLY, _GetNodeNameId(node));
else else
SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN, CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_HORDE, _GetNodeNameId(node)); SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN, CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_HORDE, _GetNodeNameId(node));
@ -435,7 +435,7 @@ void BattleGroundAB::Reset()
// call parent's class reset // call parent's class reset
BattleGround::Reset(); BattleGround::Reset();
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
{ {
m_TeamScores[i] = 0; m_TeamScores[i] = 0;
m_lastTick[i] = 0; m_lastTick[i] = 0;
@ -477,7 +477,7 @@ void BattleGroundAB::EndBattleGround(Team winner)
WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player) WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player)
{ {
BattleGroundTeamIndex teamIndex = GetTeamIndexByTeamId(player->GetTeam()); PvpTeamIndex teamIndex = GetTeamIndexByTeamId(player->GetTeam());
// Is there any occupied node for this team? // Is there any occupied node for this team?
std::vector<uint8> nodes; std::vector<uint8> nodes;

View file

@ -153,6 +153,10 @@ class BattleGroundABScore : public BattleGroundScore
public: public:
BattleGroundABScore(): BasesAssaulted(0), BasesDefended(0) {}; BattleGroundABScore(): BasesAssaulted(0), BasesDefended(0) {};
virtual ~BattleGroundABScore() {}; virtual ~BattleGroundABScore() {};
uint32 GetAttr1() const { return BasesAssaulted; }
uint32 GetAttr2() const { return BasesDefended; }
uint32 BasesAssaulted; uint32 BasesAssaulted;
uint32 BasesDefended; uint32 BasesDefended;
}; };
@ -207,13 +211,13 @@ class BattleGroundAB : public BattleGround
uint8 m_prevNodes[BG_AB_NODES_MAX]; // used for performant wordlstate-updating uint8 m_prevNodes[BG_AB_NODES_MAX]; // used for performant wordlstate-updating
BG_AB_BannerTimer m_BannerTimers[BG_AB_NODES_MAX]; BG_AB_BannerTimer m_BannerTimers[BG_AB_NODES_MAX];
uint32 m_NodeTimers[BG_AB_NODES_MAX]; uint32 m_NodeTimers[BG_AB_NODES_MAX];
uint32 m_lastTick[BG_TEAMS_COUNT]; uint32 m_lastTick[PVP_TEAM_COUNT];
uint32 m_honorScoreTicks[BG_TEAMS_COUNT]; uint32 m_honorScoreTicks[PVP_TEAM_COUNT];
uint32 m_ReputationScoreTics[BG_TEAMS_COUNT]; uint32 m_ReputationScoreTics[PVP_TEAM_COUNT];
bool m_IsInformedNearVictory; bool m_IsInformedNearVictory;
uint32 m_honorTicks; uint32 m_honorTicks;
uint32 m_ReputationTics; uint32 m_ReputationTics;
// need for achievements // need for achievements
bool m_TeamScores500Disadvantage[BG_TEAMS_COUNT]; bool m_TeamScores500Disadvantage[PVP_TEAM_COUNT];
}; };
#endif #endif

View file

@ -78,7 +78,7 @@ void BattleGroundAV::HandleKillUnit(Creature* creature, Player* killer)
return; return;
RewardReputationToTeam(BG_AV_FACTION_H, m_RepCaptain, HORDE); RewardReputationToTeam(BG_AV_FACTION_H, m_RepCaptain, HORDE);
RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), HORDE); RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), HORDE);
UpdateScore(BG_TEAM_ALLIANCE, (-1) * BG_AV_RES_CAPTAIN); UpdateScore(TEAM_INDEX_ALLIANCE, (-1) * BG_AV_RES_CAPTAIN);
// spawn destroyed aura // spawn destroyed aura
SpawnEvent(BG_AV_NodeEventCaptainDead_A, 0, true); SpawnEvent(BG_AV_NodeEventCaptainDead_A, 0, true);
break; break;
@ -87,7 +87,7 @@ void BattleGroundAV::HandleKillUnit(Creature* creature, Player* killer)
return; return;
RewardReputationToTeam(BG_AV_FACTION_A, m_RepCaptain, ALLIANCE); RewardReputationToTeam(BG_AV_FACTION_A, m_RepCaptain, ALLIANCE);
RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), ALLIANCE); RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), ALLIANCE);
UpdateScore(BG_TEAM_HORDE, (-1) * BG_AV_RES_CAPTAIN); UpdateScore(TEAM_INDEX_HORDE, (-1) * BG_AV_RES_CAPTAIN);
// spawn destroyed aura // spawn destroyed aura
SpawnEvent(BG_AV_NodeEventCaptainDead_H, 0, true); SpawnEvent(BG_AV_NodeEventCaptainDead_H, 0, true);
break; break;
@ -211,10 +211,10 @@ void BattleGroundAV::HandleQuestComplete(uint32 questid, Player* player)
RewardReputationToTeam((player->GetTeam() == ALLIANCE) ? BG_AV_FACTION_A : BG_AV_FACTION_H, reputation, player->GetTeam()); RewardReputationToTeam((player->GetTeam() == ALLIANCE) ? BG_AV_FACTION_A : BG_AV_FACTION_H, reputation, player->GetTeam());
} }
void BattleGroundAV::UpdateScore(BattleGroundTeamIndex teamIdx, int32 points) void BattleGroundAV::UpdateScore(PvpTeamIndex teamIdx, int32 points)
{ {
// note: to remove reinforcements points must be negative, for adding reinforcements points must be positive // note: to remove reinforcements points must be negative, for adding reinforcements points must be positive
MANGOS_ASSERT(teamIdx == BG_TEAM_ALLIANCE || teamIdx == BG_TEAM_HORDE); MANGOS_ASSERT(teamIdx == TEAM_INDEX_ALLIANCE || teamIdx == TEAM_INDEX_HORDE);
m_TeamScores[teamIdx] += points; // m_TeamScores is int32 - so no problems here m_TeamScores[teamIdx] += points; // m_TeamScores is int32 - so no problems here
if (points < 0) if (points < 0)
@ -223,17 +223,17 @@ void BattleGroundAV::UpdateScore(BattleGroundTeamIndex teamIdx, int32 points)
{ {
m_TeamScores[teamIdx] = 0; m_TeamScores[teamIdx] = 0;
// other team will win: // other team will win:
EndBattleGround((teamIdx == BG_TEAM_ALLIANCE) ? HORDE : ALLIANCE); EndBattleGround((teamIdx == TEAM_INDEX_ALLIANCE) ? HORDE : ALLIANCE);
} }
else if (!m_IsInformedNearLose[teamIdx] && m_TeamScores[teamIdx] < BG_AV_SCORE_NEAR_LOSE) else if (!m_IsInformedNearLose[teamIdx] && m_TeamScores[teamIdx] < BG_AV_SCORE_NEAR_LOSE)
{ {
SendMessageToAll((teamIdx == BG_TEAM_HORDE) ? LANG_BG_AV_H_NEAR_LOSE : LANG_BG_AV_A_NEAR_LOSE, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendMessageToAll((teamIdx == TEAM_INDEX_HORDE) ? LANG_BG_AV_H_NEAR_LOSE : LANG_BG_AV_A_NEAR_LOSE, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_AV_SOUND_NEAR_LOSE); PlaySoundToAll(BG_AV_SOUND_NEAR_LOSE);
m_IsInformedNearLose[teamIdx] = true; m_IsInformedNearLose[teamIdx] = true;
} }
} }
// must be called here, else it could display a negative value // must be called here, else it could display a negative value
UpdateWorldState(((teamIdx == BG_TEAM_HORDE) ? BG_AV_Horde_Score : BG_AV_Alliance_Score), m_TeamScores[teamIdx]); UpdateWorldState(((teamIdx == TEAM_INDEX_HORDE) ? BG_AV_Horde_Score : BG_AV_Alliance_Score), m_TeamScores[teamIdx]);
} }
void BattleGroundAV::Update(uint32 diff) void BattleGroundAV::Update(uint32 diff)
@ -251,7 +251,7 @@ void BattleGroundAV::Update(uint32 diff)
m_Mine_Timer[mine] -= diff; m_Mine_Timer[mine] -= diff;
if (m_Mine_Timer[mine] <= 0) if (m_Mine_Timer[mine] <= 0)
{ {
UpdateScore(BattleGroundTeamIndex(m_Mine_Owner[mine]), WORLD_STATE_ADD); UpdateScore(PvpTeamIndex(m_Mine_Owner[mine]), WORLD_STATE_ADD);
m_Mine_Timer[mine] = BG_AV_MINE_TICK_TIMER; m_Mine_Timer[mine] = BG_AV_MINE_TICK_TIMER;
} }
@ -296,18 +296,18 @@ void BattleGroundAV::AddPlayer(Player* plr)
void BattleGroundAV::EndBattleGround(Team winner) void BattleGroundAV::EndBattleGround(Team winner)
{ {
// calculate bonuskills for both teams: // calculate bonuskills for both teams:
uint32 tower_survived[BG_TEAMS_COUNT] = {0, 0}; uint32 tower_survived[PVP_TEAM_COUNT] = {0, 0};
uint32 graves_owned[BG_TEAMS_COUNT] = {0, 0}; uint32 graves_owned[PVP_TEAM_COUNT] = {0, 0};
uint32 mines_owned[BG_TEAMS_COUNT] = {0, 0}; uint32 mines_owned[PVP_TEAM_COUNT] = {0, 0};
// towers all not destroyed: // towers all not destroyed:
for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i)
if (m_Nodes[i].State == POINT_CONTROLLED) if (m_Nodes[i].State == POINT_CONTROLLED)
if (m_Nodes[i].TotalOwner == BG_AV_TEAM_ALLIANCE) if (m_Nodes[i].TotalOwner == BG_AV_TEAM_ALLIANCE)
++tower_survived[BG_TEAM_ALLIANCE]; ++tower_survived[TEAM_INDEX_ALLIANCE];
for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i)
if (m_Nodes[i].State == POINT_CONTROLLED) if (m_Nodes[i].State == POINT_CONTROLLED)
if (m_Nodes[i].TotalOwner == BG_AV_TEAM_HORDE) if (m_Nodes[i].TotalOwner == BG_AV_TEAM_HORDE)
++tower_survived[BG_TEAM_HORDE]; ++tower_survived[TEAM_INDEX_HORDE];
// graves all controlled // graves all controlled
for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i) for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i)
@ -319,9 +319,9 @@ void BattleGroundAV::EndBattleGround(Team winner)
++mines_owned[m_Mine_Owner[i]]; ++mines_owned[m_Mine_Owner[i]];
// now we have the values give the honor/reputation to the teams: // now we have the values give the honor/reputation to the teams:
Team team[BG_TEAMS_COUNT] = { ALLIANCE, HORDE }; Team team[PVP_TEAM_COUNT] = { ALLIANCE, HORDE };
uint32 faction[BG_TEAMS_COUNT] = { BG_AV_FACTION_A, BG_AV_FACTION_H }; uint32 faction[PVP_TEAM_COUNT] = { BG_AV_FACTION_A, BG_AV_FACTION_H };
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
{ {
if (tower_survived[i]) if (tower_survived[i])
{ {
@ -417,8 +417,8 @@ void BattleGroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node)
DEBUG_LOG("BattleGroundAV: player destroyed point node %i", node); DEBUG_LOG("BattleGroundAV: player destroyed point node %i", node);
MANGOS_ASSERT(m_Nodes[node].Owner != BG_AV_TEAM_NEUTRAL) MANGOS_ASSERT(m_Nodes[node].Owner != BG_AV_TEAM_NEUTRAL)
BattleGroundTeamIndex ownerTeamIdx = BattleGroundTeamIndex(m_Nodes[node].Owner); PvpTeamIndex ownerTeamIdx = PvpTeamIndex(m_Nodes[node].Owner);
Team ownerTeam = ownerTeamIdx == BG_TEAM_ALLIANCE ? ALLIANCE : HORDE; Team ownerTeam = ownerTeamIdx == TEAM_INDEX_ALLIANCE ? ALLIANCE : HORDE;
// despawn banner // despawn banner
DestroyNode(node); DestroyNode(node);
@ -531,7 +531,7 @@ void BattleGroundAV::EventPlayerDefendsPoint(Player* player, BG_AV_Nodes node)
{ {
MANGOS_ASSERT(GetStatus() == STATUS_IN_PROGRESS); MANGOS_ASSERT(GetStatus() == STATUS_IN_PROGRESS);
BattleGroundTeamIndex teamIdx = GetTeamIndexByTeamId(player->GetTeam()); PvpTeamIndex teamIdx = GetTeamIndexByTeamId(player->GetTeam());
if (m_Nodes[node].Owner == BattleGroundAVTeamIndex(teamIdx) || m_Nodes[node].State != POINT_ASSAULTED) if (m_Nodes[node].Owner == BattleGroundAVTeamIndex(teamIdx) || m_Nodes[node].State != POINT_ASSAULTED)
return; return;
@ -559,7 +559,7 @@ void BattleGroundAV::EventPlayerDefendsPoint(Player* player, BG_AV_Nodes node)
{ {
SendYell2ToAll(LANG_BG_AV_TOWER_DEFENDED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0), SendYell2ToAll(LANG_BG_AV_TOWER_DEFENDED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
GetNodeName(node), GetNodeName(node),
(teamIdx == BG_TEAM_ALLIANCE) ? LANG_BG_ALLY : LANG_BG_HORDE); (teamIdx == TEAM_INDEX_ALLIANCE) ? LANG_BG_ALLY : LANG_BG_HORDE);
UpdatePlayerScore(player, SCORE_TOWERS_DEFENDED, 1); UpdatePlayerScore(player, SCORE_TOWERS_DEFENDED, 1);
PlaySoundToAll(BG_AV_SOUND_BOTH_TOWER_DEFEND); PlaySoundToAll(BG_AV_SOUND_BOTH_TOWER_DEFEND);
} }
@ -567,17 +567,17 @@ void BattleGroundAV::EventPlayerDefendsPoint(Player* player, BG_AV_Nodes node)
{ {
SendYell2ToAll(LANG_BG_AV_GRAVE_DEFENDED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0), SendYell2ToAll(LANG_BG_AV_GRAVE_DEFENDED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
GetNodeName(node), GetNodeName(node),
(teamIdx == BG_TEAM_ALLIANCE) ? LANG_BG_ALLY : LANG_BG_HORDE); (teamIdx == TEAM_INDEX_ALLIANCE) ? LANG_BG_ALLY : LANG_BG_HORDE);
UpdatePlayerScore(player, SCORE_GRAVEYARDS_DEFENDED, 1); UpdatePlayerScore(player, SCORE_GRAVEYARDS_DEFENDED, 1);
// update the statistic for the defending player // update the statistic for the defending player
PlaySoundToAll((teamIdx == BG_TEAM_ALLIANCE) ? BG_AV_SOUND_ALLIANCE_GOOD : BG_AV_SOUND_HORDE_GOOD); PlaySoundToAll((teamIdx == TEAM_INDEX_ALLIANCE) ? BG_AV_SOUND_ALLIANCE_GOOD : BG_AV_SOUND_HORDE_GOOD);
} }
} }
void BattleGroundAV::EventPlayerAssaultsPoint(Player* player, BG_AV_Nodes node) void BattleGroundAV::EventPlayerAssaultsPoint(Player* player, BG_AV_Nodes node)
{ {
// TODO implement quest 7101, 7081 // TODO implement quest 7101, 7081
BattleGroundTeamIndex teamIdx = GetTeamIndexByTeamId(player->GetTeam()); PvpTeamIndex teamIdx = GetTeamIndexByTeamId(player->GetTeam());
DEBUG_LOG("BattleGroundAV: player assaults node %i", node); DEBUG_LOG("BattleGroundAV: player assaults node %i", node);
if (m_Nodes[node].Owner == BattleGroundAVTeamIndex(teamIdx) || BattleGroundAVTeamIndex(teamIdx) == m_Nodes[node].TotalOwner) if (m_Nodes[node].Owner == BattleGroundAVTeamIndex(teamIdx) || BattleGroundAVTeamIndex(teamIdx) == m_Nodes[node].TotalOwner)
return; return;
@ -590,19 +590,19 @@ void BattleGroundAV::EventPlayerAssaultsPoint(Player* player, BG_AV_Nodes node)
{ {
SendYell2ToAll(LANG_BG_AV_TOWER_ASSAULTED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0), SendYell2ToAll(LANG_BG_AV_TOWER_ASSAULTED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
GetNodeName(node), GetNodeName(node),
(teamIdx == BG_TEAM_ALLIANCE) ? LANG_BG_ALLY : LANG_BG_HORDE); (teamIdx == TEAM_INDEX_ALLIANCE) ? LANG_BG_ALLY : LANG_BG_HORDE);
UpdatePlayerScore(player, SCORE_TOWERS_ASSAULTED, 1); UpdatePlayerScore(player, SCORE_TOWERS_ASSAULTED, 1);
} }
else else
{ {
SendYell2ToAll(LANG_BG_AV_GRAVE_ASSAULTED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0), SendYell2ToAll(LANG_BG_AV_GRAVE_ASSAULTED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
GetNodeName(node), GetNodeName(node),
(teamIdx == BG_TEAM_ALLIANCE) ? LANG_BG_ALLY : LANG_BG_HORDE); (teamIdx == TEAM_INDEX_ALLIANCE) ? LANG_BG_ALLY : LANG_BG_HORDE);
// update the statistic for the assaulting player // update the statistic for the assaulting player
UpdatePlayerScore(player, SCORE_GRAVEYARDS_ASSAULTED, 1); UpdatePlayerScore(player, SCORE_GRAVEYARDS_ASSAULTED, 1);
} }
PlaySoundToAll((teamIdx == BG_TEAM_ALLIANCE) ? BG_AV_SOUND_ALLIANCE_ASSAULTS : BG_AV_SOUND_HORDE_ASSAULTS); PlaySoundToAll((teamIdx == TEAM_INDEX_ALLIANCE) ? BG_AV_SOUND_ALLIANCE_ASSAULTS : BG_AV_SOUND_HORDE_ASSAULTS);
} }
void BattleGroundAV::FillInitialWorldStates(WorldPacket& data, uint32& count) void BattleGroundAV::FillInitialWorldStates(WorldPacket& data, uint32& count)
@ -623,8 +623,8 @@ void BattleGroundAV::FillInitialWorldStates(WorldPacket& data, uint32& count)
if (m_Nodes[BG_AV_NODES_SNOWFALL_GRAVE].Owner == BG_AV_TEAM_NEUTRAL) // cause neutral teams aren't handled generic if (m_Nodes[BG_AV_NODES_SNOWFALL_GRAVE].Owner == BG_AV_TEAM_NEUTRAL) // cause neutral teams aren't handled generic
FillInitialWorldState(data, count, AV_SNOWFALL_N, WORLD_STATE_ADD); FillInitialWorldState(data, count, AV_SNOWFALL_N, WORLD_STATE_ADD);
FillInitialWorldState(data, count, BG_AV_Alliance_Score, m_TeamScores[BG_TEAM_ALLIANCE]); FillInitialWorldState(data, count, BG_AV_Alliance_Score, m_TeamScores[TEAM_INDEX_ALLIANCE]);
FillInitialWorldState(data, count, BG_AV_Horde_Score, m_TeamScores[BG_TEAM_HORDE]); FillInitialWorldState(data, count, BG_AV_Horde_Score, m_TeamScores[TEAM_INDEX_HORDE]);
if (GetStatus() == STATUS_IN_PROGRESS) // only if game is running the teamscores are displayed if (GetStatus() == STATUS_IN_PROGRESS) // only if game is running the teamscores are displayed
{ {
FillInitialWorldState(data, count, BG_AV_SHOW_A_SCORE, WORLD_STATE_ADD); FillInitialWorldState(data, count, BG_AV_SHOW_A_SCORE, WORLD_STATE_ADD);
@ -718,7 +718,7 @@ uint32 BattleGroundAV::GetNodeName(BG_AV_Nodes node) const
} }
} }
void BattleGroundAV::AssaultNode(BG_AV_Nodes node, BattleGroundTeamIndex teamIdx) void BattleGroundAV::AssaultNode(BG_AV_Nodes node, PvpTeamIndex teamIdx)
{ {
MANGOS_ASSERT(m_Nodes[node].TotalOwner != BattleGroundAVTeamIndex(teamIdx)); MANGOS_ASSERT(m_Nodes[node].TotalOwner != BattleGroundAVTeamIndex(teamIdx));
MANGOS_ASSERT(m_Nodes[node].Owner != BattleGroundAVTeamIndex(teamIdx)); MANGOS_ASSERT(m_Nodes[node].Owner != BattleGroundAVTeamIndex(teamIdx));
@ -758,7 +758,7 @@ void BattleGroundAV::InitNode(BG_AV_Nodes node, BattleGroundAVTeamIndex teamIdx,
m_ActiveEvents[node + BG_AV_NODES_MAX] = teamIdx * BG_AV_MAX_GRAVETYPES; m_ActiveEvents[node + BG_AV_NODES_MAX] = teamIdx * BG_AV_MAX_GRAVETYPES;
} }
void BattleGroundAV::DefendNode(BG_AV_Nodes node, BattleGroundTeamIndex teamIdx) void BattleGroundAV::DefendNode(BG_AV_Nodes node, PvpTeamIndex teamIdx)
{ {
MANGOS_ASSERT(m_Nodes[node].TotalOwner == BattleGroundAVTeamIndex(teamIdx)); MANGOS_ASSERT(m_Nodes[node].TotalOwner == BattleGroundAVTeamIndex(teamIdx));
MANGOS_ASSERT(m_Nodes[node].Owner != BattleGroundAVTeamIndex(teamIdx)); MANGOS_ASSERT(m_Nodes[node].Owner != BattleGroundAVTeamIndex(teamIdx));
@ -785,7 +785,7 @@ void BattleGroundAV::Reset()
m_RepSurviveTower = (isBGWeekend) ? BG_AV_REP_SURVIVING_TOWER_HOLIDAY : BG_AV_REP_SURVIVING_TOWER; m_RepSurviveTower = (isBGWeekend) ? BG_AV_REP_SURVIVING_TOWER_HOLIDAY : BG_AV_REP_SURVIVING_TOWER;
m_RepOwnedMine = (isBGWeekend) ? BG_AV_REP_OWNED_MINE_HOLIDAY : BG_AV_REP_OWNED_MINE; m_RepOwnedMine = (isBGWeekend) ? BG_AV_REP_OWNED_MINE_HOLIDAY : BG_AV_REP_OWNED_MINE;
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
{ {
for (uint8 j = 0; j < 9; ++j) // 9 quests getting tracked for (uint8 j = 0; j < 9; ++j) // 9 quests getting tracked
m_Team_QuestStatus[i][j] = 0; m_Team_QuestStatus[i][j] = 0;

View file

@ -208,13 +208,13 @@ enum BG_AV_WorldStates
AV_SNOWFALL_N = 1966, AV_SNOWFALL_N = 1966,
}; };
// special version with more wide values range that BattleGroundTeamIndex // special version with more wide values range that PvpTeamIndex
// BattleGroundAVTeamIndex <- BattleGroundTeamIndex cast safe // BattleGroundAVTeamIndex <- PvpTeamIndex cast safe
// BattleGroundAVTeamIndex -> BattleGroundTeamIndex cast safe and array with BG_TEAMS_COUNT elements must checked != BG_AV_TEAM_NEUTRAL before used // BattleGroundAVTeamIndex -> PvpTeamIndex cast safe and array with PVP_TEAM_COUNT elements must checked != BG_AV_TEAM_NEUTRAL before used
enum BattleGroundAVTeamIndex enum BattleGroundAVTeamIndex
{ {
BG_AV_TEAM_ALLIANCE = BG_TEAM_ALLIANCE, BG_AV_TEAM_ALLIANCE = TEAM_INDEX_ALLIANCE,
BG_AV_TEAM_HORDE = BG_TEAM_HORDE, BG_AV_TEAM_HORDE = TEAM_INDEX_HORDE,
BG_AV_TEAM_NEUTRAL = 2, // this is the neutral owner of snowfall BG_AV_TEAM_NEUTRAL = 2, // this is the neutral owner of snowfall
}; };
@ -311,6 +311,13 @@ class BattleGroundAVScore : public BattleGroundScore
public: public:
BattleGroundAVScore() : GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), SecondaryObjectives(0) {}; BattleGroundAVScore() : GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), SecondaryObjectives(0) {};
virtual ~BattleGroundAVScore() {}; virtual ~BattleGroundAVScore() {};
uint32 GetAttr1() const { return GraveyardsAssaulted; }
uint32 GetAttr2() const { return GraveyardsDefended; }
uint32 GetAttr3() const { return TowersAssaulted; }
uint32 GetAttr4() const { return TowersDefended; }
uint32 GetAttr5() const { return SecondaryObjectives; }
uint32 GraveyardsAssaulted; uint32 GraveyardsAssaulted;
uint32 GraveyardsDefended; uint32 GraveyardsDefended;
uint32 TowersAssaulted; uint32 TowersAssaulted;
@ -337,7 +344,7 @@ class BattleGroundAV : public BattleGround
virtual void Reset() override; virtual void Reset() override;
/*general stuff*/ /*general stuff*/
void UpdateScore(BattleGroundTeamIndex teamIdx, int32 points); void UpdateScore(PvpTeamIndex teamIdx, int32 points);
void UpdatePlayerScore(Player* source, uint32 type, uint32 value) override; void UpdatePlayerScore(Player* source, uint32 type, uint32 value) override;
/*handle stuff*/ // these are functions which get called from extern scripts /*handle stuff*/ // these are functions which get called from extern scripts
@ -358,10 +365,10 @@ class BattleGroundAV : public BattleGround
void EventPlayerDefendsPoint(Player* player, BG_AV_Nodes node); void EventPlayerDefendsPoint(Player* player, BG_AV_Nodes node);
void EventPlayerDestroyedPoint(BG_AV_Nodes node); void EventPlayerDestroyedPoint(BG_AV_Nodes node);
void AssaultNode(BG_AV_Nodes node, BattleGroundTeamIndex teamIdx); void AssaultNode(BG_AV_Nodes node, PvpTeamIndex teamIdx);
void DestroyNode(BG_AV_Nodes node); void DestroyNode(BG_AV_Nodes node);
void InitNode(BG_AV_Nodes node, BattleGroundAVTeamIndex teamIdx, bool tower); void InitNode(BG_AV_Nodes node, BattleGroundAVTeamIndex teamIdx, bool tower);
void DefendNode(BG_AV_Nodes node, BattleGroundTeamIndex teamIdx); void DefendNode(BG_AV_Nodes node, PvpTeamIndex teamIdx);
void PopulateNode(BG_AV_Nodes node); void PopulateNode(BG_AV_Nodes node);
@ -378,7 +385,7 @@ class BattleGroundAV : public BattleGround
void UpdateNodeWorldState(BG_AV_Nodes node); void UpdateNodeWorldState(BG_AV_Nodes node);
/*variables */ /*variables */
uint32 m_Team_QuestStatus[BG_TEAMS_COUNT][9]; // [x][y] x=team y=questcounter uint32 m_Team_QuestStatus[PVP_TEAM_COUNT][9]; // [x][y] x=team y=questcounter
BG_AV_NodeInfo m_Nodes[BG_AV_NODES_MAX]; BG_AV_NodeInfo m_Nodes[BG_AV_NODES_MAX];
@ -388,7 +395,7 @@ class BattleGroundAV : public BattleGround
int32 m_Mine_Timer[BG_AV_MAX_MINES]; int32 m_Mine_Timer[BG_AV_MAX_MINES];
uint32 m_Mine_Reclaim_Timer[BG_AV_MAX_MINES]; uint32 m_Mine_Reclaim_Timer[BG_AV_MAX_MINES];
bool m_IsInformedNearLose[BG_TEAMS_COUNT]; bool m_IsInformedNearLose[PVP_TEAM_COUNT];
uint32 m_HonorMapComplete; uint32 m_HonorMapComplete;
uint32 m_RepTowerDestruction; uint32 m_RepTowerDestruction;

View file

@ -72,6 +72,28 @@ void BattleGroundEY::Update(uint32 diff)
else else
m_flagRespawnTimer -= diff; m_flagRespawnTimer -= diff;
} }
// workaround for Fel Reaver Ruins flag capture needed on 3.3.5 only
// the original areatrigger (4514) is covered by a bigger one (4515) and is not triggered on client side
if (IsFlagPickedUp())
{
if (m_felReaverFlagTimer < diff)
{
Player* flagCarrier = sObjectMgr.GetPlayer(GetFlagCarrierGuid());
if (flagCarrier)
{
if (m_towerOwner[NODE_FEL_REAVER_RUINS] == flagCarrier->GetTeam())
{
// coords and range taken from DBC of areatrigger (4514)
if (flagCarrier->GetDistance(2044.0f, 1729.729f, 1190.03f) <= 3.0f)
EventPlayerCapturedFlag(flagCarrier, NODE_FEL_REAVER_RUINS);
}
}
m_felReaverFlagTimer = EY_FEL_REAVER_FLAG_UPDATE_TIME;
}
else
m_felReaverFlagTimer -= diff;
}
} }
void BattleGroundEY::StartingEventOpenDoors() void BattleGroundEY::StartingEventOpenDoors()
@ -85,7 +107,7 @@ void BattleGroundEY::StartingEventOpenDoors()
void BattleGroundEY::AddPoints(Team team, uint32 points) void BattleGroundEY::AddPoints(Team team, uint32 points)
{ {
BattleGroundTeamIndex team_index = GetTeamIndexByTeamId(team); PvpTeamIndex team_index = GetTeamIndexByTeamId(team);
m_TeamScores[team_index] += points; m_TeamScores[team_index] += points;
m_honorScoreTicks[team_index] += points; m_honorScoreTicks[team_index] += points;
if (m_honorScoreTicks[team_index] >= m_honorTicks) if (m_honorScoreTicks[team_index] >= m_honorTicks)
@ -231,7 +253,7 @@ void BattleGroundEY::ProcessCaptureEvent(GameObject* go, uint32 towerId, Team te
SendMessageToAll(message, CHAT_MSG_BG_SYSTEM_ALLIANCE); SendMessageToAll(message, CHAT_MSG_BG_SYSTEM_ALLIANCE);
// spawn gameobjects // spawn gameobjects
SpawnEvent(towerId, BG_TEAM_ALLIANCE, true); SpawnEvent(towerId, TEAM_INDEX_ALLIANCE, true);
} }
else if (team == HORDE) else if (team == HORDE)
{ {
@ -242,7 +264,7 @@ void BattleGroundEY::ProcessCaptureEvent(GameObject* go, uint32 towerId, Team te
SendMessageToAll(message, CHAT_MSG_BG_SYSTEM_HORDE); SendMessageToAll(message, CHAT_MSG_BG_SYSTEM_HORDE);
// spawn gameobjects // spawn gameobjects
SpawnEvent(towerId, BG_TEAM_HORDE, true); SpawnEvent(towerId, TEAM_INDEX_HORDE, true);
} }
else else
{ {
@ -310,15 +332,15 @@ void BattleGroundEY::Reset()
// call parent's class reset // call parent's class reset
BattleGround::Reset(); BattleGround::Reset();
m_TeamScores[BG_TEAM_ALLIANCE] = 0; m_TeamScores[TEAM_INDEX_ALLIANCE] = 0;
m_TeamScores[BG_TEAM_HORDE] = 0; m_TeamScores[TEAM_INDEX_HORDE] = 0;
m_towersAlliance = 0; m_towersAlliance = 0;
m_towersHorde = 0; m_towersHorde = 0;
m_honorTicks = BattleGroundMgr::IsBGWeekend(GetTypeID()) ? EY_WEEKEND_HONOR_INTERVAL : EY_NORMAL_HONOR_INTERVAL; m_honorTicks = BattleGroundMgr::IsBGWeekend(GetTypeID()) ? EY_WEEKEND_HONOR_INTERVAL : EY_NORMAL_HONOR_INTERVAL;
m_honorScoreTicks[BG_TEAM_ALLIANCE] = 0; m_honorScoreTicks[TEAM_INDEX_ALLIANCE] = 0;
m_honorScoreTicks[BG_TEAM_HORDE] = 0; m_honorScoreTicks[TEAM_INDEX_HORDE] = 0;
m_flagState = EY_FLAG_STATE_ON_BASE; m_flagState = EY_FLAG_STATE_ON_BASE;
m_flagCarrier.Clear(); m_flagCarrier.Clear();
@ -326,6 +348,7 @@ void BattleGroundEY::Reset()
m_flagRespawnTimer = 0; m_flagRespawnTimer = 0;
m_resourceUpdateTimer = 0; m_resourceUpdateTimer = 0;
m_felReaverFlagTimer = 0;
m_towerWorldState[NODE_BLOOD_ELF_TOWER] = WORLD_STATE_EY_BLOOD_ELF_TOWER_NEUTRAL; m_towerWorldState[NODE_BLOOD_ELF_TOWER] = WORLD_STATE_EY_BLOOD_ELF_TOWER_NEUTRAL;
m_towerWorldState[NODE_FEL_REAVER_RUINS] = WORLD_STATE_EY_FEL_REAVER_RUINS_NEUTRAL; m_towerWorldState[NODE_FEL_REAVER_RUINS] = WORLD_STATE_EY_FEL_REAVER_RUINS_NEUTRAL;
@ -512,8 +535,8 @@ void BattleGroundEY::FillInitialWorldStates(WorldPacket& data, uint32& count)
FillInitialWorldState(data, count, WORLD_STATE_EY_TOWER_COUNT_ALLIANCE, m_towersAlliance); FillInitialWorldState(data, count, WORLD_STATE_EY_TOWER_COUNT_ALLIANCE, m_towersAlliance);
FillInitialWorldState(data, count, WORLD_STATE_EY_TOWER_COUNT_HORDE, m_towersHorde); FillInitialWorldState(data, count, WORLD_STATE_EY_TOWER_COUNT_HORDE, m_towersHorde);
FillInitialWorldState(data, count, WORLD_STATE_EY_RESOURCES_ALLIANCE, m_TeamScores[BG_TEAM_ALLIANCE]); FillInitialWorldState(data, count, WORLD_STATE_EY_RESOURCES_ALLIANCE, m_TeamScores[TEAM_INDEX_ALLIANCE]);
FillInitialWorldState(data, count, WORLD_STATE_EY_RESOURCES_HORDE, m_TeamScores[BG_TEAM_HORDE]); FillInitialWorldState(data, count, WORLD_STATE_EY_RESOURCES_HORDE, m_TeamScores[TEAM_INDEX_HORDE]);
// tower world states // tower world states
FillInitialWorldState(data, count, WORLD_STATE_EY_BLOOD_ELF_TOWER_ALLIANCE, m_towerOwner[NODE_BLOOD_ELF_TOWER] == ALLIANCE); FillInitialWorldState(data, count, WORLD_STATE_EY_BLOOD_ELF_TOWER_ALLIANCE, m_towerOwner[NODE_BLOOD_ELF_TOWER] == ALLIANCE);

View file

@ -31,6 +31,7 @@ class BattleGround;
#define EY_FLAG_RESPAWN_TIME (10 * IN_MILLISECONDS) //10 seconds #define EY_FLAG_RESPAWN_TIME (10 * IN_MILLISECONDS) //10 seconds
#define EY_RESOURCES_UPDATE_TIME (2 * IN_MILLISECONDS) //2 seconds #define EY_RESOURCES_UPDATE_TIME (2 * IN_MILLISECONDS) //2 seconds
#define EY_FEL_REAVER_FLAG_UPDATE_TIME (1 * IN_MILLISECONDS) //1 second
enum EYWorldStates enum EYWorldStates
{ {
@ -305,9 +306,10 @@ class BattleGroundEY : public BattleGround
ObjectGuid m_towers[EY_NODES_MAX]; ObjectGuid m_towers[EY_NODES_MAX];
uint32 m_honorTicks; uint32 m_honorTicks;
uint32 m_honorScoreTicks[BG_TEAMS_COUNT]; uint32 m_honorScoreTicks[PVP_TEAM_COUNT];
uint32 m_flagRespawnTimer; uint32 m_flagRespawnTimer;
uint32 m_resourceUpdateTimer; uint32 m_resourceUpdateTimer;
uint32 m_felReaverFlagTimer;
}; };
#endif #endif

View file

@ -59,7 +59,7 @@ INSTANTIATE_SINGLETON_1(BattleGroundMgr);
BattleGroundQueue::BattleGroundQueue() BattleGroundQueue::BattleGroundQueue()
{ {
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
{ {
for (uint8 j = 0; j < MAX_BATTLEGROUND_BRACKETS; ++j) for (uint8 j = 0; j < MAX_BATTLEGROUND_BRACKETS; ++j)
{ {
@ -175,7 +175,7 @@ GroupQueueInfo* BattleGroundQueue::AddGroup(Player* leader, Group* grp, BattleGr
// compute index (if group is premade or joined a rated match) to queues // compute index (if group is premade or joined a rated match) to queues
uint32 index = 0; uint32 index = 0;
if (!isRated && !isPremade) if (!isRated && !isPremade)
index += BG_TEAMS_COUNT; // BG_QUEUE_PREMADE_* -> BG_QUEUE_NORMAL_* index += PVP_TEAM_COUNT; // BG_QUEUE_PREMADE_* -> BG_QUEUE_NORMAL_*
if (ginfo->GroupTeam == HORDE) if (ginfo->GroupTeam == HORDE)
++index; // BG_QUEUE_*_ALLIANCE -> BG_QUEUE_*_HORDE ++index; // BG_QUEUE_*_ALLIANCE -> BG_QUEUE_*_HORDE
@ -260,16 +260,16 @@ GroupQueueInfo* BattleGroundQueue::AddGroup(Player* leader, Group* grp, BattleGr
void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BattleGroundBracketId bracket_id) void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BattleGroundBracketId bracket_id)
{ {
uint32 timeInQueue = WorldTimer::getMSTimeDiff(ginfo->JoinTime, WorldTimer::getMSTime()); uint32 timeInQueue = WorldTimer::getMSTimeDiff(ginfo->JoinTime, WorldTimer::getMSTime());
uint8 team_index = BG_TEAM_ALLIANCE; // default set to BG_TEAM_ALLIANCE - or non rated arenas! uint8 team_index = TEAM_INDEX_ALLIANCE; // default set to TEAM_INDEX_ALLIANCE - or non rated arenas!
if (ginfo->arenaType == ARENA_TYPE_NONE) if (ginfo->arenaType == ARENA_TYPE_NONE)
{ {
if (ginfo->GroupTeam == HORDE) if (ginfo->GroupTeam == HORDE)
team_index = BG_TEAM_HORDE; team_index = TEAM_INDEX_HORDE;
} }
else else
{ {
if (ginfo->IsRated) if (ginfo->IsRated)
team_index = BG_TEAM_HORDE; // for rated arenas use BG_TEAM_HORDE team_index = TEAM_INDEX_HORDE; // for rated arenas use TEAM_INDEX_HORDE
} }
// store pointer to arrayindex of player that was added first // store pointer to arrayindex of player that was added first
@ -287,16 +287,16 @@ void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* g
uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BattleGroundBracketId bracket_id) uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BattleGroundBracketId bracket_id)
{ {
uint8 team_index = BG_TEAM_ALLIANCE; // default set to BG_TEAM_ALLIANCE - or non rated arenas! uint8 team_index = TEAM_INDEX_ALLIANCE; // default set to TEAM_INDEX_ALLIANCE - or non rated arenas!
if (ginfo->arenaType == ARENA_TYPE_NONE) if (ginfo->arenaType == ARENA_TYPE_NONE)
{ {
if (ginfo->GroupTeam == HORDE) if (ginfo->GroupTeam == HORDE)
team_index = BG_TEAM_HORDE; team_index = TEAM_INDEX_HORDE;
} }
else else
{ {
if (ginfo->IsRated) if (ginfo->IsRated)
team_index = BG_TEAM_HORDE; // for rated arenas use BG_TEAM_HORDE team_index = TEAM_INDEX_HORDE; // for rated arenas use TEAM_INDEX_HORDE
} }
// check if there is enought values(we always add values > 0) // check if there is enought values(we always add values > 0)
if (m_WaitTimes[team_index][bracket_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1]) if (m_WaitTimes[team_index][bracket_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1])
@ -526,13 +526,13 @@ void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BattleGroundBracketId
uint32 aliCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].size(); uint32 aliCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].size();
// index to queue which group is current // index to queue which group is current
uint32 aliIndex = 0; uint32 aliIndex = 0;
for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); ++aliIndex) for (; aliIndex < aliCount && m_SelectionPools[TEAM_INDEX_ALLIANCE].AddGroup((*Ali_itr), aliFree); ++aliIndex)
++Ali_itr; ++Ali_itr;
// the same thing for horde // the same thing for horde
GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].begin(); GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].begin();
uint32 hordeCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].size(); uint32 hordeCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].size();
uint32 hordeIndex = 0; uint32 hordeIndex = 0;
for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); ++hordeIndex) for (; hordeIndex < hordeCount && m_SelectionPools[TEAM_INDEX_HORDE].AddGroup((*Horde_itr), hordeFree); ++hordeIndex)
++Horde_itr; ++Horde_itr;
// if ofc like BG queue invitation is set in config, then we are happy // if ofc like BG queue invitation is set in config, then we are happy
@ -548,45 +548,45 @@ void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BattleGroundBracketId
*/ */
// At first we need to compare free space in bg and our selection pool // At first we need to compare free space in bg and our selection pool
int32 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount()); int32 diffAli = aliFree - int32(m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount());
int32 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()); int32 diffHorde = hordeFree - int32(m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount());
while (abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0)) while (abs(diffAli - diffHorde) > 1 && (m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() > 0 || m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount() > 0))
{ {
// each cycle execution we need to kick at least 1 group // each cycle execution we need to kick at least 1 group
if (diffAli < diffHorde) if (diffAli < diffHorde)
{ {
// kick alliance group, add to pool new group if needed // kick alliance group, add to pool new group if needed
if (m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli)) if (m_SelectionPools[TEAM_INDEX_ALLIANCE].KickGroup(diffHorde - diffAli))
{ {
for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); ++aliIndex) for (; aliIndex < aliCount && m_SelectionPools[TEAM_INDEX_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); ++aliIndex)
++Ali_itr; ++Ali_itr;
} }
// if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break; // if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
if (!m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount()) if (!m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount())
{ {
if (aliFree <= diffHorde + 1) if (aliFree <= diffHorde + 1)
break; break;
m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli); m_SelectionPools[TEAM_INDEX_HORDE].KickGroup(diffHorde - diffAli);
} }
} }
else else
{ {
// kick horde group, add to pool new group if needed // kick horde group, add to pool new group if needed
if (m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde)) if (m_SelectionPools[TEAM_INDEX_HORDE].KickGroup(diffAli - diffHorde))
{ {
for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); ++hordeIndex) for (; hordeIndex < hordeCount && m_SelectionPools[TEAM_INDEX_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); ++hordeIndex)
++Horde_itr; ++Horde_itr;
} }
if (!m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) if (!m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount())
{ {
if (hordeFree <= diffAli + 1) if (hordeFree <= diffAli + 1)
break; break;
m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde); m_SelectionPools[TEAM_INDEX_ALLIANCE].KickGroup(diffAli - diffHorde);
} }
} }
// count diffs after small update // count diffs after small update
diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount()); diffAli = aliFree - int32(m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount());
diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()); diffHorde = hordeFree - int32(m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount());
} }
} }
@ -610,12 +610,12 @@ bool BattleGroundQueue::CheckPremadeMatch(BattleGroundBracketId bracket_id, uint
if (ali_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end()) if (ali_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end())
{ {
m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam); m_SelectionPools[TEAM_INDEX_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam); m_SelectionPools[TEAM_INDEX_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
// add groups/players from normal queue to size of bigger group // add groups/players from normal queue to size of bigger group
uint32 maxPlayers = std::max(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()); uint32 maxPlayers = std::max(m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount(), m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount());
GroupsQueueType::const_iterator itr; GroupsQueueType::const_iterator itr;
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
{ {
for (itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr) for (itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
{ {
@ -633,7 +633,7 @@ bool BattleGroundQueue::CheckPremadeMatch(BattleGroundBracketId bracket_id, uint
// if first is invited to BG and seconds timer expired, but we can ignore it, because players have only 80 seconds to click to enter bg // if first is invited to BG and seconds timer expired, but we can ignore it, because players have only 80 seconds to click to enter bg
// and when they click or after 80 seconds the queue info is removed from queue // and when they click or after 80 seconds the queue info is removed from queue
uint32 time_before = WorldTimer::getMSTime() - sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH); uint32 time_before = WorldTimer::getMSTime() - sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
{ {
if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty()) if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
{ {
@ -653,8 +653,8 @@ bool BattleGroundQueue::CheckPremadeMatch(BattleGroundBracketId bracket_id, uint
// this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam // this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BattleGroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers) bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BattleGroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers)
{ {
GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT]; GroupsQueueType::const_iterator itr_team[PVP_TEAM_COUNT];
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
{ {
itr_team[i] = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr_team[i] = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
for (; itr_team[i] != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i])) for (; itr_team[i] != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
@ -668,43 +668,43 @@ bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BattleGround
} }
} }
// try to invite same number of players - this cycle may cause longer wait time even if there are enough players in queue, but we want ballanced bg // try to invite same number of players - this cycle may cause longer wait time even if there are enough players in queue, but we want ballanced bg
uint32 j = BG_TEAM_ALLIANCE; uint32 j = TEAM_INDEX_ALLIANCE;
if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount()) if (m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() < m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount())
j = BG_TEAM_HORDE; j = TEAM_INDEX_HORDE;
if (sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE) != 0 if (sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE) != 0
&& m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers) && m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount() >= minPlayers)
{ {
// we will try to invite more groups to team with less players indexed by j // we will try to invite more groups to team with less players indexed by j
++(itr_team[j]); // this will not cause a crash, because for cycle above reached break; ++(itr_team[j]); // this will not cause a crash, because for cycle above reached break;
for (; itr_team[j] != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j])) for (; itr_team[j] != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
{ {
if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID) if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID)
if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount())) if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % PVP_TEAM_COUNT].GetPlayerCount()))
break; break;
} }
// do not allow to start bg with more than 2 players more on 1 faction // do not allow to start bg with more than 2 players more on 1 faction
if (abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2) if (abs((int32)(m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() - m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount())) > 2)
return false; return false;
} }
// allow 1v0 if debug bg // allow 1v0 if debug bg
if (sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())) if (sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount() || m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount()))
return true; return true;
// return true if there are enough players in selection pools - enable to work .debug bg command correctly // return true if there are enough players in selection pools - enable to work .debug bg command correctly
return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers; return m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() >= minPlayers;
} }
// this method will check if we can invite players to same faction skirmish match // this method will check if we can invite players to same faction skirmish match
bool BattleGroundQueue::CheckSkirmishForSameFaction(BattleGroundBracketId bracket_id, uint32 minPlayersPerTeam) bool BattleGroundQueue::CheckSkirmishForSameFaction(BattleGroundBracketId bracket_id, uint32 minPlayersPerTeam)
{ {
if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam) if (m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() < minPlayersPerTeam)
return false; return false;
BattleGroundTeamIndex teamIdx = BG_TEAM_ALLIANCE; PvpTeamIndex teamIdx = TEAM_INDEX_ALLIANCE;
BattleGroundTeamIndex otherTeamIdx = BG_TEAM_HORDE; PvpTeamIndex otherTeamIdx = TEAM_INDEX_HORDE;
Team otherTeamId = HORDE; Team otherTeamId = HORDE;
if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam) if (m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() == minPlayersPerTeam)
{ {
teamIdx = BG_TEAM_HORDE; teamIdx = TEAM_INDEX_HORDE;
otherTeamIdx = BG_TEAM_ALLIANCE; otherTeamIdx = TEAM_INDEX_ALLIANCE;
otherTeamId = ALLIANCE; otherTeamId = ALLIANCE;
} }
// clear other team's selection // clear other team's selection
@ -782,16 +782,16 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
// and iterator is invalid // and iterator is invalid
// clear selection pools // clear selection pools
m_SelectionPools[BG_TEAM_ALLIANCE].Init(); m_SelectionPools[TEAM_INDEX_ALLIANCE].Init();
m_SelectionPools[BG_TEAM_HORDE].Init(); m_SelectionPools[TEAM_INDEX_HORDE].Init();
// call a function that does the job for us // call a function that does the job for us
FillPlayersToBG(bg, bracket_id); FillPlayersToBG(bg, bracket_id);
// now everything is set, invite players // now everything is set, invite players
for (GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.end(); ++citr) for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_INDEX_ALLIANCE].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_INDEX_ALLIANCE].SelectedGroups.end(); ++citr)
InviteGroupToBG((*citr), bg, (*citr)->GroupTeam); InviteGroupToBG((*citr), bg, (*citr)->GroupTeam);
for (GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++citr) for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_INDEX_HORDE].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_INDEX_HORDE].SelectedGroups.end(); ++citr)
InviteGroupToBG((*citr), bg, (*citr)->GroupTeam); InviteGroupToBG((*citr), bg, (*citr)->GroupTeam);
if (!bg->HasFreeSlots()) if (!bg->HasFreeSlots())
@ -853,8 +853,8 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
} }
} }
m_SelectionPools[BG_TEAM_ALLIANCE].Init(); m_SelectionPools[TEAM_INDEX_ALLIANCE].Init();
m_SelectionPools[BG_TEAM_HORDE].Init(); m_SelectionPools[TEAM_INDEX_HORDE].Init();
if (bg_template->isBattleGround()) if (bg_template->isBattleGround())
{ {
@ -869,14 +869,14 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
return; return;
} }
// invite those selection pools // invite those selection pools
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
for (GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr) for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_INDEX_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_INDEX_ALLIANCE + i].SelectedGroups.end(); ++citr)
InviteGroupToBG((*citr), bg2, (*citr)->GroupTeam); InviteGroupToBG((*citr), bg2, (*citr)->GroupTeam);
// start bg // start bg
bg2->StartBattleGround(); bg2->StartBattleGround();
// clear structures // clear structures
m_SelectionPools[BG_TEAM_ALLIANCE].Init(); m_SelectionPools[TEAM_INDEX_ALLIANCE].Init();
m_SelectionPools[BG_TEAM_HORDE].Init(); m_SelectionPools[TEAM_INDEX_HORDE].Init();
} }
} }
@ -896,8 +896,8 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
} }
// invite those selection pools // invite those selection pools
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
for (GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr) for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_INDEX_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_INDEX_ALLIANCE + i].SelectedGroups.end(); ++citr)
InviteGroupToBG((*citr), bg2, (*citr)->GroupTeam); InviteGroupToBG((*citr), bg2, (*citr)->GroupTeam);
// start bg // start bg
bg2->StartBattleGround(); bg2->StartBattleGround();
@ -942,7 +942,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
// we need to find 2 teams which will play next game // we need to find 2 teams which will play next game
GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT]; GroupsQueueType::iterator itr_team[PVP_TEAM_COUNT];
// optimalization : --- we dont need to use selection_pools - each update we select max 2 groups // optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
@ -967,40 +967,40 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
// if we don't have, we must try to continue search in same queue // if we don't have, we must try to continue search in same queue
// tmp variables are correctly set // tmp variables are correctly set
// this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) if (m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount())
{ {
itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE]; itr_team[TEAM_INDEX_ALLIANCE] = itr_team[TEAM_INDEX_HORDE];
++itr_team[BG_TEAM_ALLIANCE]; ++itr_team[TEAM_INDEX_ALLIANCE];
for (; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE])) for (; itr_team[TEAM_INDEX_ALLIANCE] != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[TEAM_INDEX_ALLIANCE]))
{ {
if (!(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID if (!(*itr_team[TEAM_INDEX_ALLIANCE])->IsInvitedToBGInstanceGUID
&& (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating) && (((*itr_team[TEAM_INDEX_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[TEAM_INDEX_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
|| (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime)) || (*itr_team[TEAM_INDEX_ALLIANCE])->JoinTime < discardTime))
{ {
m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam); m_SelectionPools[TEAM_INDEX_ALLIANCE].AddGroup((*itr_team[TEAM_INDEX_ALLIANCE]), MaxPlayersPerTeam);
break; break;
} }
} }
} }
// this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount()) if (m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() == 0 && m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount())
{ {
itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE]; itr_team[TEAM_INDEX_HORDE] = itr_team[TEAM_INDEX_ALLIANCE];
++itr_team[BG_TEAM_HORDE]; ++itr_team[TEAM_INDEX_HORDE];
for (; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE])) for (; itr_team[TEAM_INDEX_HORDE] != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[TEAM_INDEX_HORDE]))
{ {
if (!(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID if (!(*itr_team[TEAM_INDEX_HORDE])->IsInvitedToBGInstanceGUID
&& (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating) && (((*itr_team[TEAM_INDEX_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[TEAM_INDEX_HORDE])->ArenaTeamRating <= arenaMaxRating)
|| (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime)) || (*itr_team[TEAM_INDEX_HORDE])->JoinTime < discardTime))
{ {
m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam); m_SelectionPools[TEAM_INDEX_HORDE].AddGroup((*itr_team[TEAM_INDEX_HORDE]), MaxPlayersPerTeam);
break; break;
} }
} }
} }
// if we have 2 teams, then start new arena and invite players! // if we have 2 teams, then start new arena and invite players!
if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) if (m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount() && m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount())
{ {
BattleGround* arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, bracketEntry, arenaType, true); BattleGround* arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, bracketEntry, arenaType, true);
if (!arena) if (!arena)
@ -1009,28 +1009,28 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
return; return;
} }
(*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating; (*(itr_team[TEAM_INDEX_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[TEAM_INDEX_HORDE]))->ArenaTeamRating;
DEBUG_LOG("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating); DEBUG_LOG("setting oposite teamrating for team %u to %u", (*(itr_team[TEAM_INDEX_ALLIANCE]))->ArenaTeamId, (*(itr_team[TEAM_INDEX_ALLIANCE]))->OpponentsTeamRating);
(*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating; (*(itr_team[TEAM_INDEX_HORDE]))->OpponentsTeamRating = (*(itr_team[TEAM_INDEX_ALLIANCE]))->ArenaTeamRating;
DEBUG_LOG("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating); DEBUG_LOG("setting oposite teamrating for team %u to %u", (*(itr_team[TEAM_INDEX_HORDE]))->ArenaTeamId, (*(itr_team[TEAM_INDEX_HORDE]))->OpponentsTeamRating);
// now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer // now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer
if ((*(itr_team[BG_TEAM_ALLIANCE]))->GroupTeam != ALLIANCE) if ((*(itr_team[TEAM_INDEX_ALLIANCE]))->GroupTeam != ALLIANCE)
{ {
// add to alliance queue // add to alliance queue
m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE])); m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[TEAM_INDEX_ALLIANCE]));
// erase from horde queue // erase from horde queue
m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]); m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[TEAM_INDEX_ALLIANCE]);
itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); itr_team[TEAM_INDEX_ALLIANCE] = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
} }
if ((*(itr_team[BG_TEAM_HORDE]))->GroupTeam != HORDE) if ((*(itr_team[TEAM_INDEX_HORDE]))->GroupTeam != HORDE)
{ {
m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE])); m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[TEAM_INDEX_HORDE]));
m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]); m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[TEAM_INDEX_HORDE]);
itr_team[BG_TEAM_HORDE] = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].begin(); itr_team[TEAM_INDEX_HORDE] = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].begin();
} }
InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE); InviteGroupToBG(*(itr_team[TEAM_INDEX_ALLIANCE]), arena, ALLIANCE);
InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE); InviteGroupToBG(*(itr_team[TEAM_INDEX_HORDE]), arena, HORDE);
DEBUG_LOG("Starting rated arena match!"); DEBUG_LOG("Starting rated arena match!");

View file

@ -134,12 +134,12 @@ class BattleGroundQueue
}; };
// one selection pool for horde, other one for alliance // one selection pool for horde, other one for alliance
SelectionPool m_SelectionPools[BG_TEAMS_COUNT]; SelectionPool m_SelectionPools[PVP_TEAM_COUNT];
bool InviteGroupToBG(GroupQueueInfo* ginfo, BattleGround* bg, Team side); bool InviteGroupToBG(GroupQueueInfo* ginfo, BattleGround* bg, Team side);
uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME]; uint32 m_WaitTimes[PVP_TEAM_COUNT][MAX_BATTLEGROUND_BRACKETS][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME];
uint32 m_WaitTimeLastPlayer[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS]; uint32 m_WaitTimeLastPlayer[PVP_TEAM_COUNT][MAX_BATTLEGROUND_BRACKETS];
uint32 m_SumOfWaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS]; uint32 m_SumOfWaitTimes[PVP_TEAM_COUNT][MAX_BATTLEGROUND_BRACKETS];
}; };
/* /*

View file

@ -48,52 +48,52 @@ void BattleGroundWS::Update(uint32 diff)
if (GetStatus() == STATUS_IN_PROGRESS) if (GetStatus() == STATUS_IN_PROGRESS)
{ {
if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) if (m_FlagState[TEAM_INDEX_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN)
{ {
m_FlagsTimer[BG_TEAM_ALLIANCE] -= diff; m_FlagsTimer[TEAM_INDEX_ALLIANCE] -= diff;
if (m_FlagsTimer[BG_TEAM_ALLIANCE] < 0) if (m_FlagsTimer[TEAM_INDEX_ALLIANCE] < 0)
{ {
m_FlagsTimer[BG_TEAM_ALLIANCE] = 0; m_FlagsTimer[TEAM_INDEX_ALLIANCE] = 0;
RespawnFlag(ALLIANCE, true); RespawnFlag(ALLIANCE, true);
} }
} }
if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) if (m_FlagState[TEAM_INDEX_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND)
{ {
m_FlagsDropTimer[BG_TEAM_ALLIANCE] -= diff; m_FlagsDropTimer[TEAM_INDEX_ALLIANCE] -= diff;
if (m_FlagsDropTimer[BG_TEAM_ALLIANCE] < 0) if (m_FlagsDropTimer[TEAM_INDEX_ALLIANCE] < 0)
{ {
m_FlagsDropTimer[BG_TEAM_ALLIANCE] = 0; m_FlagsDropTimer[TEAM_INDEX_ALLIANCE] = 0;
RespawnDroppedFlag(ALLIANCE); RespawnDroppedFlag(ALLIANCE);
} }
} }
if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) if (m_FlagState[TEAM_INDEX_HORDE] == BG_WS_FLAG_STATE_WAIT_RESPAWN)
{ {
m_FlagsTimer[BG_TEAM_HORDE] -= diff; m_FlagsTimer[TEAM_INDEX_HORDE] -= diff;
if (m_FlagsTimer[BG_TEAM_HORDE] < 0) if (m_FlagsTimer[TEAM_INDEX_HORDE] < 0)
{ {
m_FlagsTimer[BG_TEAM_HORDE] = 0; m_FlagsTimer[TEAM_INDEX_HORDE] = 0;
RespawnFlag(HORDE, true); RespawnFlag(HORDE, true);
} }
} }
if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) if (m_FlagState[TEAM_INDEX_HORDE] == BG_WS_FLAG_STATE_ON_GROUND)
{ {
m_FlagsDropTimer[BG_TEAM_HORDE] -= diff; m_FlagsDropTimer[TEAM_INDEX_HORDE] -= diff;
if (m_FlagsDropTimer[BG_TEAM_HORDE] < 0) if (m_FlagsDropTimer[TEAM_INDEX_HORDE] < 0)
{ {
m_FlagsDropTimer[BG_TEAM_HORDE] = 0; m_FlagsDropTimer[TEAM_INDEX_HORDE] = 0;
RespawnDroppedFlag(HORDE); RespawnDroppedFlag(HORDE);
} }
} }
if (m_EndTimer <= diff) if (m_EndTimer <= diff)
{ {
if (m_TeamScores[BG_TEAM_ALLIANCE] > m_TeamScores[BG_TEAM_HORDE]) if (m_TeamScores[TEAM_INDEX_ALLIANCE] > m_TeamScores[TEAM_INDEX_HORDE])
EndBattleGround(ALLIANCE); EndBattleGround(ALLIANCE);
else if (m_TeamScores[BG_TEAM_ALLIANCE] < m_TeamScores[BG_TEAM_HORDE]) else if (m_TeamScores[TEAM_INDEX_ALLIANCE] < m_TeamScores[TEAM_INDEX_HORDE])
EndBattleGround(HORDE); EndBattleGround(HORDE);
else else
{ {
@ -141,13 +141,13 @@ void BattleGroundWS::RespawnFlag(Team team, bool captured)
if (team == ALLIANCE) if (team == ALLIANCE)
{ {
DEBUG_LOG("Respawn Alliance flag"); DEBUG_LOG("Respawn Alliance flag");
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE; m_FlagState[TEAM_INDEX_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE;
SpawnEvent(WS_EVENT_FLAG_A, 0, true); SpawnEvent(WS_EVENT_FLAG_A, 0, true);
} }
else else
{ {
DEBUG_LOG("Respawn Horde flag"); DEBUG_LOG("Respawn Horde flag");
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE; m_FlagState[TEAM_INDEX_HORDE] = BG_WS_FLAG_STATE_ON_BASE;
SpawnEvent(WS_EVENT_FLAG_H, 0, true); SpawnEvent(WS_EVENT_FLAG_H, 0, true);
} }
@ -197,11 +197,11 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player* source)
return; return;
ClearHordeFlagCarrier(); // must be before aura remove to prevent 2 events (drop+capture) at the same time ClearHordeFlagCarrier(); // must be before aura remove to prevent 2 events (drop+capture) at the same time
// horde flag in base (but not respawned yet) // horde flag in base (but not respawned yet)
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; m_FlagState[TEAM_INDEX_HORDE] = BG_WS_FLAG_STATE_WAIT_RESPAWN;
// Drop Horde Flag from Player // Drop Horde Flag from Player
source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
if (m_TeamScores[BG_TEAM_ALLIANCE] < BG_WS_MAX_TEAM_SCORE) if (m_TeamScores[TEAM_INDEX_ALLIANCE] < BG_WS_MAX_TEAM_SCORE)
m_TeamScores[BG_TEAM_ALLIANCE] += 1; m_TeamScores[TEAM_INDEX_ALLIANCE] += 1;
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE);
RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE); RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE);
} }
@ -211,11 +211,11 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player* source)
return; return;
ClearAllianceFlagCarrier(); // must be before aura remove to prevent 2 events (drop+capture) at the same time ClearAllianceFlagCarrier(); // must be before aura remove to prevent 2 events (drop+capture) at the same time
// alliance flag in base (but not respawned yet) // alliance flag in base (but not respawned yet)
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; m_FlagState[TEAM_INDEX_ALLIANCE] = BG_WS_FLAG_STATE_WAIT_RESPAWN;
// Drop Alliance Flag from Player // Drop Alliance Flag from Player
source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
if (m_TeamScores[BG_TEAM_HORDE] < BG_WS_MAX_TEAM_SCORE) if (m_TeamScores[TEAM_INDEX_HORDE] < BG_WS_MAX_TEAM_SCORE)
m_TeamScores[BG_TEAM_HORDE] += 1; m_TeamScores[TEAM_INDEX_HORDE] += 1;
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE);
RewardReputationToTeam(889, m_ReputationCapture, HORDE); RewardReputationToTeam(889, m_ReputationCapture, HORDE);
} }
@ -237,9 +237,9 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player* source)
UpdatePlayerScore(source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures UpdatePlayerScore(source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures
Team winner = TEAM_NONE; Team winner = TEAM_NONE;
if (m_TeamScores[BG_TEAM_ALLIANCE] == BG_WS_MAX_TEAM_SCORE) if (m_TeamScores[TEAM_INDEX_ALLIANCE] == BG_WS_MAX_TEAM_SCORE)
winner = ALLIANCE; winner = ALLIANCE;
else if (m_TeamScores[BG_TEAM_HORDE] == BG_WS_MAX_TEAM_SCORE) else if (m_TeamScores[TEAM_INDEX_HORDE] == BG_WS_MAX_TEAM_SCORE)
winner = HORDE; winner = HORDE;
if (winner) if (winner)
@ -296,7 +296,7 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player* source)
{ {
ClearHordeFlagCarrier(); ClearHordeFlagCarrier();
source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_GROUND; m_FlagState[TEAM_INDEX_HORDE] = BG_WS_FLAG_STATE_ON_GROUND;
source->CastSpell(source, BG_WS_SPELL_WARSONG_FLAG_DROPPED, true); source->CastSpell(source, BG_WS_SPELL_WARSONG_FLAG_DROPPED, true);
set = true; set = true;
} }
@ -309,7 +309,7 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player* source)
{ {
ClearAllianceFlagCarrier(); ClearAllianceFlagCarrier();
source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_GROUND; m_FlagState[TEAM_INDEX_ALLIANCE] = BG_WS_FLAG_STATE_ON_GROUND;
source->CastSpell(source, BG_WS_SPELL_SILVERWING_FLAG_DROPPED, true); source->CastSpell(source, BG_WS_SPELL_SILVERWING_FLAG_DROPPED, true);
set = true; set = true;
} }
@ -354,7 +354,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player* source, GameObject* target
PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP); PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP);
SpawnEvent(WS_EVENT_FLAG_A, 0, false); SpawnEvent(WS_EVENT_FLAG_A, 0, false);
SetAllianceFlagCarrier(source->GetObjectGuid()); SetAllianceFlagCarrier(source->GetObjectGuid());
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER; m_FlagState[TEAM_INDEX_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER;
// update world state to show correct flag carrier // update world state to show correct flag carrier
UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER); UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER);
UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1); UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1);
@ -370,7 +370,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player* source, GameObject* target
PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP); PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP);
SpawnEvent(WS_EVENT_FLAG_H, 0, false); SpawnEvent(WS_EVENT_FLAG_H, 0, false);
SetHordeFlagCarrier(source->GetObjectGuid()); SetHordeFlagCarrier(source->GetObjectGuid());
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER; m_FlagState[TEAM_INDEX_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER;
// update world state to show correct flag carrier // update world state to show correct flag carrier
UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER); UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER);
UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1); UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1);
@ -397,7 +397,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player* source, GameObject* target
SpawnEvent(WS_EVENT_FLAG_A, 0, false); SpawnEvent(WS_EVENT_FLAG_A, 0, false);
SetAllianceFlagCarrier(source->GetObjectGuid()); SetAllianceFlagCarrier(source->GetObjectGuid());
source->CastSpell(source, BG_WS_SPELL_SILVERWING_FLAG, true); source->CastSpell(source, BG_WS_SPELL_SILVERWING_FLAG, true);
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER; m_FlagState[TEAM_INDEX_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER;
UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER); UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER);
UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1); UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1);
} }
@ -425,7 +425,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player* source, GameObject* target
SpawnEvent(WS_EVENT_FLAG_H, 0, false); SpawnEvent(WS_EVENT_FLAG_H, 0, false);
SetHordeFlagCarrier(source->GetObjectGuid()); SetHordeFlagCarrier(source->GetObjectGuid());
source->CastSpell(source, BG_WS_SPELL_WARSONG_FLAG, true); source->CastSpell(source, BG_WS_SPELL_WARSONG_FLAG, true);
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER; m_FlagState[TEAM_INDEX_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER;
UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER); UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER);
UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1); UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1);
} }
@ -478,9 +478,9 @@ void BattleGroundWS::UpdateFlagState(Team team, uint32 value)
void BattleGroundWS::UpdateTeamScore(Team team) void BattleGroundWS::UpdateTeamScore(Team team)
{ {
if (team == ALLIANCE) if (team == ALLIANCE)
UpdateWorldState(BG_WS_FLAG_CAPTURES_ALLIANCE, m_TeamScores[BG_TEAM_ALLIANCE]); UpdateWorldState(BG_WS_FLAG_CAPTURES_ALLIANCE, m_TeamScores[TEAM_INDEX_ALLIANCE]);
else else
UpdateWorldState(BG_WS_FLAG_CAPTURES_HORDE, m_TeamScores[BG_TEAM_HORDE]); UpdateWorldState(BG_WS_FLAG_CAPTURES_HORDE, m_TeamScores[TEAM_INDEX_HORDE]);
} }
void BattleGroundWS::HandleAreaTrigger(Player* source, uint32 trigger) void BattleGroundWS::HandleAreaTrigger(Player* source, uint32 trigger)
@ -501,12 +501,12 @@ void BattleGroundWS::HandleAreaTrigger(Player* source, uint32 trigger)
case 3709: // Horde elixir of berserk spawn case 3709: // Horde elixir of berserk spawn
break; break;
case 3646: // Alliance Flag spawn case 3646: // Alliance Flag spawn
if (m_FlagState[BG_TEAM_HORDE] && !m_FlagState[BG_TEAM_ALLIANCE]) if (m_FlagState[TEAM_INDEX_HORDE] && !m_FlagState[TEAM_INDEX_ALLIANCE])
if (GetHordeFlagCarrierGuid() == source->GetObjectGuid()) if (GetHordeFlagCarrierGuid() == source->GetObjectGuid())
EventPlayerCapturedFlag(source); EventPlayerCapturedFlag(source);
break; break;
case 3647: // Horde Flag spawn case 3647: // Horde Flag spawn
if (m_FlagState[BG_TEAM_ALLIANCE] && !m_FlagState[BG_TEAM_HORDE]) if (m_FlagState[TEAM_INDEX_ALLIANCE] && !m_FlagState[TEAM_INDEX_HORDE])
if (GetAllianceFlagCarrierGuid() == source->GetObjectGuid()) if (GetAllianceFlagCarrierGuid() == source->GetObjectGuid())
EventPlayerCapturedFlag(source); EventPlayerCapturedFlag(source);
break; break;
@ -532,7 +532,7 @@ void BattleGroundWS::Reset()
m_ActiveEvents[WS_EVENT_FLAG_A] = BG_EVENT_NONE; m_ActiveEvents[WS_EVENT_FLAG_A] = BG_EVENT_NONE;
m_ActiveEvents[WS_EVENT_FLAG_H] = BG_EVENT_NONE; m_ActiveEvents[WS_EVENT_FLAG_H] = BG_EVENT_NONE;
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
{ {
m_DroppedFlagGuid[i].Clear(); m_DroppedFlagGuid[i].Clear();
m_FlagState[i] = BG_WS_FLAG_STATE_ON_BASE; m_FlagState[i] = BG_WS_FLAG_STATE_ON_BASE;
@ -620,31 +620,31 @@ WorldSafeLocsEntry const* BattleGroundWS::GetClosestGraveYard(Player* player)
void BattleGroundWS::FillInitialWorldStates(WorldPacket& data, uint32& count) void BattleGroundWS::FillInitialWorldStates(WorldPacket& data, uint32& count)
{ {
FillInitialWorldState(data, count, BG_WS_FLAG_CAPTURES_ALLIANCE, m_TeamScores[BG_TEAM_ALLIANCE]); FillInitialWorldState(data, count, BG_WS_FLAG_CAPTURES_ALLIANCE, m_TeamScores[TEAM_INDEX_ALLIANCE]);
FillInitialWorldState(data, count, BG_WS_FLAG_CAPTURES_HORDE, m_TeamScores[BG_TEAM_HORDE]); FillInitialWorldState(data, count, BG_WS_FLAG_CAPTURES_HORDE, m_TeamScores[TEAM_INDEX_HORDE]);
if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) if (m_FlagState[TEAM_INDEX_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND)
FillInitialWorldState(data, count, BG_WS_FLAG_UNK_ALLIANCE, -1); FillInitialWorldState(data, count, BG_WS_FLAG_UNK_ALLIANCE, -1);
else if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER) else if (m_FlagState[TEAM_INDEX_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER)
FillInitialWorldState(data, count, BG_WS_FLAG_UNK_ALLIANCE, 1); FillInitialWorldState(data, count, BG_WS_FLAG_UNK_ALLIANCE, 1);
else else
FillInitialWorldState(data, count, BG_WS_FLAG_UNK_ALLIANCE, 0); FillInitialWorldState(data, count, BG_WS_FLAG_UNK_ALLIANCE, 0);
if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) if (m_FlagState[TEAM_INDEX_HORDE] == BG_WS_FLAG_STATE_ON_GROUND)
FillInitialWorldState(data, count, BG_WS_FLAG_UNK_HORDE, -1); FillInitialWorldState(data, count, BG_WS_FLAG_UNK_HORDE, -1);
else if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER) else if (m_FlagState[TEAM_INDEX_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER)
FillInitialWorldState(data, count, BG_WS_FLAG_UNK_HORDE, 1); FillInitialWorldState(data, count, BG_WS_FLAG_UNK_HORDE, 1);
else else
FillInitialWorldState(data, count, BG_WS_FLAG_UNK_HORDE, 0); FillInitialWorldState(data, count, BG_WS_FLAG_UNK_HORDE, 0);
FillInitialWorldState(data, count, BG_WS_FLAG_CAPTURES_MAX, BG_WS_MAX_TEAM_SCORE); FillInitialWorldState(data, count, BG_WS_FLAG_CAPTURES_MAX, BG_WS_MAX_TEAM_SCORE);
if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER) if (m_FlagState[TEAM_INDEX_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER)
FillInitialWorldState(data, count, BG_WS_FLAG_STATE_HORDE, 2); FillInitialWorldState(data, count, BG_WS_FLAG_STATE_HORDE, 2);
else else
FillInitialWorldState(data, count, BG_WS_FLAG_STATE_HORDE, 1); FillInitialWorldState(data, count, BG_WS_FLAG_STATE_HORDE, 1);
if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER) if (m_FlagState[TEAM_INDEX_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER)
FillInitialWorldState(data, count, BG_WS_FLAG_STATE_ALLIANCE, 2); FillInitialWorldState(data, count, BG_WS_FLAG_STATE_ALLIANCE, 2);
else else
FillInitialWorldState(data, count, BG_WS_FLAG_STATE_ALLIANCE, 1); FillInitialWorldState(data, count, BG_WS_FLAG_STATE_ALLIANCE, 1);

View file

@ -87,6 +87,10 @@ class BattleGroundWGScore : public BattleGroundScore
public: public:
BattleGroundWGScore() : FlagCaptures(0), FlagReturns(0) {}; BattleGroundWGScore() : FlagCaptures(0), FlagReturns(0) {};
virtual ~BattleGroundWGScore() {}; virtual ~BattleGroundWGScore() {};
uint32 GetAttr1() const { return FlagCaptures; }
uint32 GetAttr2() const { return FlagReturns; }
uint32 FlagCaptures; uint32 FlagCaptures;
uint32 FlagReturns; uint32 FlagReturns;
}; };
@ -154,10 +158,10 @@ class BattleGroundWS : public BattleGround
ObjectGuid m_flagCarrierAlliance; ObjectGuid m_flagCarrierAlliance;
ObjectGuid m_flagCarrierHorde; ObjectGuid m_flagCarrierHorde;
ObjectGuid m_DroppedFlagGuid[BG_TEAMS_COUNT]; ObjectGuid m_DroppedFlagGuid[PVP_TEAM_COUNT];
uint8 m_FlagState[BG_TEAMS_COUNT]; uint8 m_FlagState[PVP_TEAM_COUNT];
int32 m_FlagsTimer[BG_TEAMS_COUNT]; int32 m_FlagsTimer[PVP_TEAM_COUNT];
int32 m_FlagsDropTimer[BG_TEAMS_COUNT]; int32 m_FlagsDropTimer[PVP_TEAM_COUNT];
uint32 m_ReputationCapture; uint32 m_ReputationCapture;
uint32 m_HonorWinKills; uint32 m_HonorWinKills;

View file

@ -50,6 +50,7 @@
#include "Util.h" #include "Util.h"
#include "GridNotifiers.h" #include "GridNotifiers.h"
#include "GridNotifiersImpl.h" #include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "WaypointMovementGenerator.h" #include "WaypointMovementGenerator.h"
#include <cctype> #include <cctype>
#include <iostream> #include <iostream>

View file

@ -6101,9 +6101,7 @@ bool ChatHandler::HandleGMFlyCommand(char* args)
if (!target) if (!target)
target = m_session->GetPlayer(); target = m_session->GetPlayer();
WorldPacket data; target->SetCanFly(value);
target->BuildMoveSetCanFlyPacket(&data, value, 0);
target->SendMessageToSet(&data, true);
PSendSysMessage(LANG_COMMAND_FLYMODE_STATUS, GetNameLink(target).c_str(), args); PSendSysMessage(LANG_COMMAND_FLYMODE_STATUS, GetNameLink(target).c_str(), args);
return true; return true;
} }
@ -7310,6 +7308,64 @@ bool ChatHandler::HandleMmapTestArea(char* args)
return true; return true;
} }
// use ".mmap testheight 10" selecting any creature/player
bool ChatHandler::HandleMmapTestHeight(char* args)
{
float radius = 0.0f;
ExtractFloat(&args, radius);
if (radius > 40.0f)
radius = 40.0f;
Unit* unit = getSelectedUnit();
Player* player = m_session->GetPlayer();
if (!unit)
unit = player;
if (unit->GetTypeId() == TYPEID_UNIT)
{
if (radius < 0.1f)
radius = static_cast<Creature*>(unit)->GetRespawnRadius();
}
else
{
if (unit->GetTypeId() != TYPEID_PLAYER)
{
PSendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
return false;
}
}
if (radius < 0.1f)
{
PSendSysMessage("Provided spawn radius for %s is too small. Using 5.0f instead.", unit->GetGuidStr().c_str());
radius = 5.0f;
}
float gx, gy, gz;
unit->GetPosition(gx, gy, gz);
Creature* summoned = unit->SummonCreature(VISUAL_WAYPOINT, gx, gy, gz + 0.5f, 0, TEMPSUMMON_TIMED_DESPAWN, 20000);
summoned->CastSpell(summoned, 8599, false);
uint32 tries = 1;
uint32 successes = 0;
uint32 startTime = WorldTimer::getMSTime();
for (; tries < 500; ++tries)
{
unit->GetPosition(gx, gy, gz);
if (unit->GetMap()->GetReachableRandomPosition(unit, gx, gy, gz, radius))
{
unit->SummonCreature(VISUAL_WAYPOINT, gx, gy, gz, 0, TEMPSUMMON_TIMED_DESPAWN, 15000);
++successes;
if (successes >= 100)
break;
}
}
uint32 genTime = WorldTimer::getMSTimeDiff(startTime, WorldTimer::getMSTime());
PSendSysMessage("Generated %u valid points for %u try in %ums.", successes, tries, genTime);
return true;
}
bool ChatHandler::HandleServerResetAllRaidCommand(char* args) bool ChatHandler::HandleServerResetAllRaidCommand(char* args)
{ {
PSendSysMessage("Global raid instances reset, all players in raid instances will be teleported to homebind!"); PSendSysMessage("Global raid instances reset, all players in raid instances will be teleported to homebind!");

View file

@ -1117,10 +1117,10 @@ bool ChatHandler::HandleDebugSpellCoefsCommand(char* args)
char const* dotDamageStr = GetMangosString(LANG_DOT_DAMAGE); char const* dotDamageStr = GetMangosString(LANG_DOT_DAMAGE);
PSendSysMessage(LANG_SPELLCOEFS, spellid, isDirectHeal ? directHealStr : directDamageStr, PSendSysMessage(LANG_SPELLCOEFS, spellid, isDirectHeal ? directHealStr : directDamageStr,
direct_calc, direct_calc * 1.88f, bonus ? bonus->direct_damage : 0.0f, bonus ? bonus->ap_bonus : 0.0f); direct_calc, direct_calc * SCALE_SPELLPOWER_HEALING, bonus ? bonus->direct_damage : 0.0f, bonus ? bonus->ap_bonus : 0.0f);
PSendSysMessage(LANG_SPELLCOEFS, spellid, isDotHeal ? dotHealStr : dotDamageStr, PSendSysMessage(LANG_SPELLCOEFS, spellid, isDotHeal ? dotHealStr : dotDamageStr,
dot_calc, dot_calc * 1.88f, bonus ? bonus->dot_damage : 0.0f, bonus ? bonus->ap_dot_bonus : 0.0f); dot_calc, dot_calc * SCALE_SPELLPOWER_HEALING, bonus ? bonus->dot_damage : 0.0f, bonus ? bonus->ap_dot_bonus : 0.0f);
return true; return true;
} }

View file

@ -118,7 +118,7 @@ template<>
void ConfusedMovementGenerator<Player>::Finalize(Player& unit) void ConfusedMovementGenerator<Player>::Finalize(Player& unit)
{ {
unit.clearUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_CONFUSED_MOVE); unit.clearUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_CONFUSED_MOVE);
unit.StopMoving(); unit.StopMoving(true);
} }
template<> template<>

View file

@ -37,16 +37,17 @@
template<class T> template<class T>
void FleeingMovementGenerator<T>::_setTargetLocation(T& owner) void FleeingMovementGenerator<T>::_setTargetLocation(T& owner)
{ {
if (!&owner)
return;
// ignore in case other no reaction state // ignore in case other no reaction state
if (owner.hasUnitState((UNIT_STAT_CAN_NOT_REACT | UNIT_STAT_NOT_MOVE) & ~UNIT_STAT_FLEEING)) if (owner.hasUnitState((UNIT_STAT_CAN_NOT_REACT | UNIT_STAT_NOT_MOVE) & ~UNIT_STAT_FLEEING))
return; return;
float x, y, z; float x, y, z;
if (!_getPoint(owner, x, y, z)) if (!_getPoint(owner, x, y, z))
{
// random point not found recheck later
i_nextCheckTime.Reset(50);
return; return;
}
owner.addUnitState(UNIT_STAT_FLEEING_MOVE); owner.addUnitState(UNIT_STAT_FLEEING_MOVE);
@ -55,7 +56,8 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T& owner)
path.calculate(x, y, z); path.calculate(x, y, z);
if (path.getPathType() & PATHFIND_NOPATH) if (path.getPathType() & PATHFIND_NOPATH)
{ {
i_nextCheckTime.Reset(urand(1000, 1500)); // path not found recheck later
i_nextCheckTime.Reset(50);
return; return;
} }
@ -69,9 +71,6 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T& owner)
template<class T> template<class T>
bool FleeingMovementGenerator<T>::_getPoint(T& owner, float& x, float& y, float& z) bool FleeingMovementGenerator<T>::_getPoint(T& owner, float& x, float& y, float& z)
{ {
if (!&owner)
return false;
float dist_from_caster, angle_to_caster; float dist_from_caster, angle_to_caster;
if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGuid)) if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGuid))
{ {
@ -109,12 +108,23 @@ bool FleeingMovementGenerator<T>::_getPoint(T& owner, float& x, float& y, float&
x = curr_x + dist * cos(angle); x = curr_x + dist * cos(angle);
y = curr_y + dist * sin(angle); y = curr_y + dist * sin(angle);
z = curr_z; z = curr_z + 0.5f;
// try to fix z
if (!owner.GetMap()->GetHeightInRange(owner.GetPhaseMask(), x, y, z))
return false;
if (owner.GetTypeId() == TYPEID_PLAYER) if (owner.GetTypeId() == TYPEID_PLAYER)
owner.GetMap()->GetHitPosition(curr_x, curr_y, curr_z, x, y, z, owner.GetPhaseMask(), -0.1f); {
// check any collision
owner.UpdateAllowedPositionZ(x, y, z); float testZ = z + 0.5f; // needed to avoid some false positive hit detection of terrain or passable little object
if (owner.GetMap()->GetHitPosition(curr_x, curr_y, curr_z + 0.5f, x, y, testZ, owner.GetPhaseMask(), -0.1f))
{
z = testZ;
if (!owner.GetMap()->GetHeightInRange(owner.GetPhaseMask(), x, y, z))
return false;
}
}
return true; return true;
} }

View file

@ -509,6 +509,16 @@ void MotionMaster::MoveJump(float x, float y, float z, float horizontalSpeed, fl
Mutate(new EffectMovementGenerator(id)); Mutate(new EffectMovementGenerator(id));
} }
void MotionMaster::MoveDestination(float x, float y, float z, float o, float horizontalSpeed, float max_height, Unit* target)
{
Movement::MoveSplineInit init(*m_owner);
init.MoveTo(x, y, z);
init.SetParabolic(max_height, 0);
init.SetVelocity(horizontalSpeed);
target ? init.SetFacing(target) : init.SetFacing(o);
init.Launch();
}
void MotionMaster::MoveFall() void MotionMaster::MoveFall()
{ {
// use larger distance for vmap height search than in most other cases // use larger distance for vmap height search than in most other cases

View file

@ -117,6 +117,7 @@ class MotionMaster : private std::stack<MovementGenerator*>
void MoveTaxiFlight(uint32 path, uint32 pathnode); void MoveTaxiFlight(uint32 path, uint32 pathnode);
void MoveDistract(uint32 timeLimit); void MoveDistract(uint32 timeLimit);
void MoveJump(float x, float y, float z, float horizontalSpeed, float max_height, uint32 id = 0); void MoveJump(float x, float y, float z, float horizontalSpeed, float max_height, uint32 id = 0);
void MoveDestination(float x, float y, float z, float o, float horizontalSpeed, float max_height, Unit* target = nullptr);
void MoveFall(); void MoveFall();
void MoveFlyOrLand(uint32 id, float x, float y, float z, bool liftOff); void MoveFlyOrLand(uint32 id, float x, float y, float z, bool liftOff);

View file

@ -333,6 +333,7 @@ void FlightPathMovementGenerator::Finalize(Player& player)
player.Unmount(); player.Unmount();
player.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); player.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
player.SetClientControl(&player, 1);
if (player.m_taxi.empty()) if (player.m_taxi.empty())
{ {

View file

@ -55,7 +55,7 @@ AggressorAI::MoveInLineOfSight(Unit* u)
return; return;
if (m_creature->CanInitiateAttack() && u->IsTargetableForAttack() && if (m_creature->CanInitiateAttack() && u->IsTargetableForAttack() &&
m_creature->IsHostileTo(u) && u->isInAccessablePlaceFor(m_creature)) m_creature->IsHostileTo(u) && u->IsInAccessablePlaceFor(m_creature))
{ {
float attackRadius = m_creature->GetAttackDistance(u); float attackRadius = m_creature->GetAttackDistance(u);
if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->IsWithinLOSInMap(u)) if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->IsWithinLOSInMap(u))

View file

@ -208,6 +208,10 @@ void Creature::AddToWorld()
{ GetMap()->GetObjectsStore().insert<Creature>(GetObjectGuid(), (Creature*)this); } { GetMap()->GetObjectsStore().insert<Creature>(GetObjectGuid(), (Creature*)this); }
Unit::AddToWorld(); Unit::AddToWorld();
// Make active if required
if (sWorld.isForceLoadMap(GetMapId()) || (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_ACTIVE))
SetActiveObjectState(true);
} }
void Creature::RemoveFromWorld() void Creature::RemoveFromWorld()
@ -384,7 +388,14 @@ bool Creature::InitEntry(uint32 Entry, CreatureData const* data /*=NULL*/, GameE
UpdateSpeed(MOVE_WALK, false); UpdateSpeed(MOVE_WALK, false);
UpdateSpeed(MOVE_RUN, false); UpdateSpeed(MOVE_RUN, false);
SetLevitate(cinfo->InhabitType & INHABIT_AIR); SetLevitate((cinfo->InhabitType & INHABIT_AIR) != 0); // TODO: may not be correct to send opcode at this point (already handled by UPDATE_OBJECT createObject)
// check if we need to add swimming movement. TODO: i thing movement flags should be computed automatically at each movement of creature so we need a sort of UpdateMovementFlags() method
if (cinfo->InhabitType & INHABIT_WATER && // check inhabit type water
!(cinfo->ExtraFlags & CREATURE_EXTRA_FLAG_WALK_IN_WATER) && // check if creature is forced to walk (crabs, giant,...)
data && // check if there is data to get creature spawn pos
GetMap()->GetTerrain()->IsSwimmable(data->posX, data->posY, data->posZ, minfo->bounding_radius)) // check if creature is in water and have enough space to swim
m_movementInfo.AddMovementFlag(MOVEFLAG_SWIMMING); // add swimming movement
// checked at loading // checked at loading
m_defaultMovementType = MovementGeneratorType(cinfo->MovementType); m_defaultMovementType = MovementGeneratorType(cinfo->MovementType);
@ -485,8 +496,10 @@ uint32 Creature::ChooseDisplayId(const CreatureInfo* cinfo, const CreatureData*
// if mod2 use mod2 unless mod2 has modelid_alt_model (then both by 50%-chance) // if mod2 use mod2 unless mod2 has modelid_alt_model (then both by 50%-chance)
// if mod1 use mod1 // if mod1 use mod1
// model selected here may be replaced with other_gender using own function // The follow decision tree needs to be updated if MAX_CREATURE_MODEL is changed.
static_assert(MAX_CREATURE_MODEL == 4, "Need to update model selection code for new or removed model fields");
// model selected here may be replaced with other_gender using own function
if (cinfo->ModelId[3] && cinfo->ModelId[2] && cinfo->ModelId[1] && cinfo->ModelId[0]) if (cinfo->ModelId[3] && cinfo->ModelId[2] && cinfo->ModelId[1] && cinfo->ModelId[0])
{ {
display_id = cinfo->ModelId[urand(0, 3)]; display_id = cinfo->ModelId[urand(0, 3)];
@ -1159,6 +1172,9 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
CreatureInfo const* cinfo = GetCreatureInfo(); CreatureInfo const* cinfo = GetCreatureInfo();
if (cinfo) if (cinfo)
{ {
// The following if-else assumes that there are 4 model fields and needs updating if this is changed.
static_assert(MAX_CREATURE_MODEL == 4, "Need to update custom model check for new/removed model fields.");
if (displayId != cinfo->ModelId[0] && displayId != cinfo->ModelId[1] && if (displayId != cinfo->ModelId[0] && displayId != cinfo->ModelId[1] &&
displayId != cinfo->ModelId[2] && displayId != cinfo->ModelId[3]) displayId != cinfo->ModelId[2] && displayId != cinfo->ModelId[3])
{ {
@ -1765,6 +1781,35 @@ bool Creature::IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectInd
return Unit::IsImmuneToSpellEffect(spellInfo, index, castOnSelf); return Unit::IsImmuneToSpellEffect(spellInfo, index, castOnSelf);
} }
// Set loot status. Also handle remove corpse timer
void Creature::SetLootStatus(CreatureLootStatus status)
{
if (status <= m_lootStatus)
return;
m_lootStatus = status;
switch (status)
{
case CREATURE_LOOT_STATUS_LOOTED:
if (m_creatureInfo->SkinningLootId)
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
else
RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
break;
case CREATURE_LOOT_STATUS_SKINNED:
m_corpseDecayTimer = 0; // remove corpse at next update
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
break;
case CREATURE_LOOT_STATUS_SKIN_AVAILABLE:
SetFlag(UNIT_FIELD_FLAGS, UNIT_DYNFLAG_LOOTABLE);
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
break;
default:
break;
}
}
// return true if this creature is tapped by the player or by a member of his group. // return true if this creature is tapped by the player or by a member of his group.
bool Creature::IsTappedBy(Player const* player) const bool Creature::IsTappedBy(Player const* player) const
{ {
@ -2038,7 +2083,7 @@ bool Creature::IsOutOfThreatArea(Unit* pVictim) const
if (!pVictim->IsTargetableForAttack()) if (!pVictim->IsTargetableForAttack())
return true; return true;
if (!pVictim->isInAccessablePlaceFor(this)) if (!pVictim->IsInAccessablePlaceFor(this))
return true; return true;
if (!pVictim->IsVisibleForOrDetect(this, this, false)) if (!pVictim->IsVisibleForOrDetect(this, this, false))
@ -2771,6 +2816,54 @@ void Creature::SetLevitate(bool enable)
} }
} }
void Creature::SetSwim(bool enable)
{
if (enable)
m_movementInfo.AddMovementFlag(MOVEFLAG_SWIMMING);
else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_SWIMMING);
WorldPacket data(enable ? SMSG_SPLINE_MOVE_START_SWIM : SMSG_SPLINE_MOVE_STOP_SWIM);
data << GetPackGUID();
SendMessageToSet(&data, true);
}
void Creature::SetCanFly(bool enable)
{
if (enable)
m_movementInfo.AddMovementFlag(MOVEFLAG_CAN_FLY);
else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_CAN_FLY);
WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_FLYING : SMSG_SPLINE_MOVE_UNSET_FLYING, 9);
data << GetPackGUID();
SendMessageToSet(&data, true);
}
void Creature::SetFeatherFall(bool enable)
{
if (enable)
m_movementInfo.AddMovementFlag(MOVEFLAG_SAFE_FALL);
else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_SAFE_FALL);
WorldPacket data(enable ? SMSG_SPLINE_MOVE_FEATHER_FALL : SMSG_SPLINE_MOVE_NORMAL_FALL);
data << GetPackGUID();
SendMessageToSet(&data, true);
}
void Creature::SetHover(bool enable)
{
if (enable)
m_movementInfo.AddMovementFlag(MOVEFLAG_HOVER);
else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_HOVER);
WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_HOVER : SMSG_SPLINE_MOVE_UNSET_HOVER, 9);
data << GetPackGUID();
SendMessageToSet(&data, false);
}
void Creature::SetRoot(bool enable) void Creature::SetRoot(bool enable)
{ {
if (enable) if (enable)

View file

@ -542,11 +542,11 @@ class Creature : public Unit
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
uint32 GetCorpseDelay() const { return m_corpseDelay; } uint32 GetCorpseDelay() const { return m_corpseDelay; }
bool IsRacialLeader() const { return GetCreatureInfo()->RacialLeader; } bool IsRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_CIVILIAN; } bool IsCivilian() const { return (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_CIVILIAN) != 0; }
bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_GUARD; } bool IsGuard() const { return (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_GUARD) != 0; }
bool CanWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; } bool CanWalk() const { return (GetCreatureInfo()->InhabitType & INHABIT_GROUND) != 0; }
bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; } bool CanSwim() const { return (GetCreatureInfo()->InhabitType & INHABIT_WATER) != 0; }
bool IsSwimming() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_SWIMMING))); } bool IsSwimming() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_SWIMMING))); }
bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_FLY_ANIM) || m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_LEVITATING | MOVEFLAG_CAN_FLY)); } bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_FLY_ANIM) || m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_LEVITATING | MOVEFLAG_CAN_FLY)); }
bool IsFlying() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_FLYING | MOVEFLAG_LEVITATING))); } bool IsFlying() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_FLYING | MOVEFLAG_LEVITATING))); }
@ -560,6 +560,7 @@ class Creature : public Unit
bool IsImmuneToSpell(SpellEntry const* spellInfo, bool castOnSelf) override; bool IsImmuneToSpell(SpellEntry const* spellInfo, bool castOnSelf) override;
bool IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectIndex index, bool castOnSelf) const override; bool IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectIndex index, bool castOnSelf) const override;
void SetLootStatus(CreatureLootStatus status);
bool IsTappedBy(Player const* player) const; bool IsTappedBy(Player const* player) const;
bool IsElite() const bool IsElite() const
@ -591,6 +592,10 @@ class Creature : public Unit
void SetWalk(bool enable, bool asDefault = true); void SetWalk(bool enable, bool asDefault = true);
void SetLevitate(bool enable); void SetLevitate(bool enable);
void SetSwim(bool enable) override;
void SetCanFly(bool enable) override;
void SetFeatherFall(bool enable) override;
void SetHover(bool enable) override;
void SetRoot(bool enable) override; void SetRoot(bool enable) override;
void SetWaterWalk(bool enable) override; void SetWaterWalk(bool enable) override;
@ -818,6 +823,7 @@ class Creature : public Unit
uint32 m_lootMoney; uint32 m_lootMoney;
ObjectGuid m_lootRecipientGuid; // player who will have rights for looting if m_lootGroupRecipient==0 or group disbanded ObjectGuid m_lootRecipientGuid; // player who will have rights for looting if m_lootGroupRecipient==0 or group disbanded
uint32 m_lootGroupRecipientId; // group who will have rights for looting if set and exist uint32 m_lootGroupRecipientId; // group who will have rights for looting if set and exist
CreatureLootStatus m_lootStatus; // loot status (used to know when we could loot, pickpocket or skin)
/// Timers /// Timers
uint32 m_corpseDecayTimer; // (msecs)timer for death or corpse disappearance uint32 m_corpseDecayTimer; // (msecs)timer for death or corpse disappearance

View file

@ -182,6 +182,7 @@ inline bool IsTimerBasedEvent(EventAI_Type type)
case EVENT_T_MISSING_AURA: case EVENT_T_MISSING_AURA:
case EVENT_T_TARGET_MISSING_AURA: case EVENT_T_TARGET_MISSING_AURA:
case EVENT_T_RANGE: case EVENT_T_RANGE:
case EVENT_T_ENERGY:
return true; return true;
default: default:
return false; return false;
@ -276,6 +277,13 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
pHolder.UpdateRepeatTimer(m_creature, event.spell_hit.repeatMin, event.spell_hit.repeatMax); pHolder.UpdateRepeatTimer(m_creature, event.spell_hit.repeatMin, event.spell_hit.repeatMax);
break; break;
case EVENT_T_RANGE: case EVENT_T_RANGE:
if (!m_creature->IsInCombat() || !m_creature->getVictim() || !m_creature->IsInMap(m_creature->getVictim()))
return false;
// DISCUSS TODO - Likely replace IsInRange check with CombatReach checks (as used rather for such checks)
if (!m_creature->IsInRange(m_creature->getVictim(), (float)event.range.minDist, (float)event.range.maxDist))
return false;
// Repeat Timers // Repeat Timers
pHolder.UpdateRepeatTimer(m_creature, event.range.repeatMin, event.range.repeatMax); pHolder.UpdateRepeatTimer(m_creature, event.range.repeatMin, event.range.repeatMax);
break; break;
@ -394,6 +402,9 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
break; break;
case EVENT_T_AURA: case EVENT_T_AURA:
{ {
if (!m_creature->IsInCombat())
return false;
SpellAuraHolder* holder = m_creature->GetSpellAuraHolder(event.buffed.spellId); SpellAuraHolder* holder = m_creature->GetSpellAuraHolder(event.buffed.spellId);
if (!holder || holder->GetStackAmount() < event.buffed.amount) if (!holder || holder->GetStackAmount() < event.buffed.amount)
return false; return false;
@ -419,6 +430,9 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
} }
case EVENT_T_MISSING_AURA: case EVENT_T_MISSING_AURA:
{ {
if (!m_creature->IsInCombat())
return false;
SpellAuraHolder* holder = m_creature->GetSpellAuraHolder(event.buffed.spellId); SpellAuraHolder* holder = m_creature->GetSpellAuraHolder(event.buffed.spellId);
if (holder && holder->GetStackAmount() >= event.buffed.amount) if (holder && holder->GetStackAmount() >= event.buffed.amount)
return false; return false;
@ -444,6 +458,21 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
} }
case EVENT_T_RECEIVE_AI_EVENT: case EVENT_T_RECEIVE_AI_EVENT:
break; break;
case EVENT_T_ENERGY:
{
if (!m_creature->IsInCombat() || !m_creature->GetMaxPower(POWER_ENERGY))
return false;
uint32 perc = (m_creature->GetPower(POWER_ENERGY) * 100) / m_creature->GetMaxPower(POWER_ENERGY);
if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
return false;
LOG_PROCESS_EVENT;
// Repeat Timers
pHolder.UpdateRepeatTimer(m_creature, event.percent_range.repeatMin, event.percent_range.repeatMax);
break;
}
default: default:
sLog.outErrorEventAI("Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); sLog.outErrorEventAI("Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type);
break; break;
@ -478,7 +507,7 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
if (count) if (count)
{ {
// select action number from found amount // select action number from found amount
uint32 idx = urand(0, count - 1); uint32 idx = rnd % count;
// find selected action, skipping not used // find selected action, skipping not used
uint32 j = 0; uint32 j = 0;
@ -520,17 +549,17 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
if (action.type == ACTION_T_TEXT) if (action.type == ACTION_T_TEXT)
{ {
if (action.text.TextId[1] && action.text.TextId[2]) if (action.text.TextId[1] && action.text.TextId[2])
textId = action.text.TextId[urand(0, 2)]; textId = action.text.TextId[rnd % 3];
else if (action.text.TextId[1] && urand(0, 1)) else if (action.text.TextId[1] && (rnd % 2))
textId = action.text.TextId[1]; textId = action.text.TextId[1];
else else
textId = action.text.TextId[0]; textId = action.text.TextId[0];
} }
// ACTION_T_CHANCED_TEXT, chance hits // ACTION_T_CHANCED_TEXT, chance hits
else if (urand(0, 99) < action.chanced_text.chance) else if ((rnd % 100) < action.chanced_text.chance)
{ {
if (action.chanced_text.TextId[0] && action.chanced_text.TextId[1]) if (action.chanced_text.TextId[0] && action.chanced_text.TextId[1])
textId = action.chanced_text.TextId[urand(0, 1)]; textId = action.chanced_text.TextId[rnd % 2];
else else
textId = action.chanced_text.TextId[0]; textId = action.chanced_text.TextId[0];
} }
@ -839,9 +868,9 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
Creature* pCreature = NULL; Creature* pCreature = NULL;
if ((*i).second.SpawnTimeSecs) if ((*i).second.SpawnTimeSecs)
pCreature = m_creature->SummonCreature(action.summon_id.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs); pCreature = m_creature->SummonCreature(action.summon_id.creatureId, i->second.position_x, i->second.position_y, i->second.position_z, i->second.orientation, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, i->second.SpawnTimeSecs);
else else
pCreature = m_creature->SummonCreature(action.summon_id.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OOC_DESPAWN, 0); pCreature = m_creature->SummonCreature(action.summon_id.creatureId, i->second.position_x, i->second.position_y, i->second.position_z, i->second.orientation, TEMPSUMMON_TIMED_OOC_DESPAWN, 0);
if (!pCreature) if (!pCreature)
sLog.outErrorEventAI("failed to spawn creature %u. EventId %d.Creature %d", action.summon_id.creatureId, EventId, m_creature->GetEntry()); sLog.outErrorEventAI("failed to spawn creature %u. EventId %d.Creature %d", action.summon_id.creatureId, EventId, m_creature->GetEntry());
@ -1035,29 +1064,26 @@ void CreatureEventAI::Reset()
{ {
m_EventUpdateTime = EVENT_UPDATE_TIME; m_EventUpdateTime = EVENT_UPDATE_TIME;
m_EventDiff = 0; m_EventDiff = 0;
m_throwAIEventStep = 0; m_throwAIEventStep = 0;
// Reset all events to enabled // Reset all events to enabled
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
CreatureEventAI_Event const& event = (*i).Event; CreatureEventAI_Event const& event = i->Event;
switch (event.event_type) switch (event.event_type)
{ {
// Reset all out of combat timers // Reset all out of combat timers
case EVENT_T_TIMER_OOC: case EVENT_T_TIMER_OOC:
{ {
if ((*i).UpdateRepeatTimer(m_creature, event.timer.initialMin, event.timer.initialMax)) if (i->UpdateRepeatTimer(m_creature, event.timer.initialMin, event.timer.initialMax))
(*i).Enabled = true; i->Enabled = true;
break; break;
} }
default: default:
// TODO: enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void Aggro()
//i->Enabled = true;
//i->Time = 0;
break; break;
// default:
// TODO: enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void Aggro()
//(*i).Enabled = true;
//(*i).Time = 0;
// break;
} }
} }
} }
@ -1066,7 +1092,7 @@ void CreatureEventAI::JustReachedHome()
{ {
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_REACHED_HOME) if (i->Event.event_type == EVENT_T_REACHED_HOME)
ProcessEvent(*i); ProcessEvent(*i);
} }
@ -1079,18 +1105,16 @@ void CreatureEventAI::EnterEvadeMode()
m_creature->DeleteThreatList(); m_creature->DeleteThreatList();
m_creature->CombatStop(true); m_creature->CombatStop(true);
if (m_creature->IsAlive()) // only alive creatures that are not on transport can return to home position
if (m_creature->IsAlive() && !m_creature->IsBoarded())
m_creature->GetMotionMaster()->MoveTargetedHome(); m_creature->GetMotionMaster()->MoveTargetedHome();
m_creature->SetLootRecipient(NULL); m_creature->SetLootRecipient(nullptr);
if (m_bEmptyList)
return;
// Handle Evade events // Handle Evade events
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_EVADE) if (i->Event.event_type == EVENT_T_EVADE)
ProcessEvent(*i); ProcessEvent(*i);
} }
} }
@ -1112,7 +1136,7 @@ void CreatureEventAI::JustDied(Unit* killer)
// Handle On Death events // Handle On Death events
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_DEATH) if (i->Event.event_type == EVENT_T_DEATH)
ProcessEvent(*i, killer); ProcessEvent(*i, killer);
} }
@ -1127,7 +1151,7 @@ void CreatureEventAI::KilledUnit(Unit* victim)
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_KILL) if (i->Event.event_type == EVENT_T_KILL)
ProcessEvent(*i, victim); ProcessEvent(*i, victim);
} }
} }
@ -1136,7 +1160,7 @@ void CreatureEventAI::JustSummoned(Creature* pUnit)
{ {
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_SUMMONED_UNIT) if (i->Event.event_type == EVENT_T_SUMMONED_UNIT)
ProcessEvent(*i, pUnit); ProcessEvent(*i, pUnit);
} }
} }
@ -1145,7 +1169,7 @@ void CreatureEventAI::SummonedCreatureJustDied(Creature* pUnit)
{ {
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_SUMMONED_JUST_DIED) if (i->Event.event_type == EVENT_T_SUMMONED_JUST_DIED)
ProcessEvent(*i, pUnit); ProcessEvent(*i, pUnit);
} }
} }
@ -1154,12 +1178,12 @@ void CreatureEventAI::SummonedCreatureDespawn(Creature* pUnit)
{ {
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_SUMMONED_JUST_DESPAWN) if (i->Event.event_type == EVENT_T_SUMMONED_JUST_DESPAWN)
ProcessEvent(*i, pUnit); ProcessEvent(*i, pUnit);
} }
} }
void CreatureEventAI::ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 miscValue) void CreatureEventAI::ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 /*miscValue*/)
{ {
MANGOS_ASSERT(pSender); MANGOS_ASSERT(pSender);
@ -1169,29 +1193,29 @@ void CreatureEventAI::ReceiveAIEvent(AIEventType eventType, Creature* pSender, U
itr->Event.receiveAIEvent.eventType == eventType && (!itr->Event.receiveAIEvent.senderEntry || itr->Event.receiveAIEvent.senderEntry == pSender->GetEntry())) itr->Event.receiveAIEvent.eventType == eventType && (!itr->Event.receiveAIEvent.senderEntry || itr->Event.receiveAIEvent.senderEntry == pSender->GetEntry()))
ProcessEvent(*itr, pInvoker, pSender); ProcessEvent(*itr, pInvoker, pSender);
} }
} }
void CreatureEventAI::EnterCombat(Unit* enemy) void CreatureEventAI::EnterCombat(Unit* enemy)
{ {
// Check for on combat start events // Check for on combat start events
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
CreatureEventAI_Event const& event = (*i).Event; CreatureEventAI_Event const& event = i->Event;
switch (event.event_type) switch (event.event_type)
{ {
case EVENT_T_AGGRO: case EVENT_T_AGGRO:
(*i).Enabled = true; i->Enabled = true;
ProcessEvent(*i, enemy); ProcessEvent(*i, enemy);
break; break;
// Reset all in combat timers // Reset all in combat timers
case EVENT_T_TIMER_IN_COMBAT: case EVENT_T_TIMER_IN_COMBAT:
if ((*i).UpdateRepeatTimer(m_creature, event.timer.initialMin, event.timer.initialMax)) if (i->UpdateRepeatTimer(m_creature, event.timer.initialMin, event.timer.initialMax))
(*i).Enabled = true; i->Enabled = true;
break; break;
// All normal events need to be re-enabled and their time set to 0 // All normal events need to be re-enabled and their time set to 0
default: default:
(*i).Enabled = true; i->Enabled = true;
(*i).Time = 0; i->Time = 0;
break; break;
} }
} }
@ -1221,21 +1245,21 @@ void CreatureEventAI::MoveInLineOfSight(Unit* who)
return; return;
// Check for OOC LOS Event // Check for OOC LOS Event
if (!m_creature->getVictim()) if (m_HasOOCLoSEvent && !m_creature->getVictim())
{ {
for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr) for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr)
{ {
if ((*itr).Event.event_type == EVENT_T_OOC_LOS) if (itr->Event.event_type == EVENT_T_OOC_LOS)
{ {
// can trigger if closer than fMaxAllowedRange // can trigger if closer than fMaxAllowedRange
float fMaxAllowedRange = (float)(*itr).Event.ooc_los.maxRange; float fMaxAllowedRange = (float)itr->Event.ooc_los.maxRange;
// if range is ok and we are actually in LOS // if friendly event && who is not hostile OR hostile event && who is hostile
if (m_creature->IsWithinDistInMap(who, fMaxAllowedRange) && m_creature->IsWithinLOSInMap(who)) if ((itr->Event.ooc_los.noHostile && !m_creature->IsHostileTo(who)) ||
((!itr->Event.ooc_los.noHostile) && m_creature->IsHostileTo(who)))
{ {
// if friendly event&&who is not hostile OR hostile event&&who is hostile // if range is ok and we are actually in LOS
if (((*itr).Event.ooc_los.noHostile && !m_creature->IsHostileTo(who)) || if (m_creature->IsWithinDistInMap(who, fMaxAllowedRange) && m_creature->IsWithinLOSInMap(who))
((!(*itr).Event.ooc_los.noHostile) && m_creature->IsHostileTo(who)))
ProcessEvent(*itr, who); ProcessEvent(*itr, who);
} }
} }
@ -1246,7 +1270,7 @@ void CreatureEventAI::MoveInLineOfSight(Unit* who)
return; return;
if (m_creature->CanInitiateAttack() && who->IsTargetableForAttack() && if (m_creature->CanInitiateAttack() && who->IsTargetableForAttack() &&
m_creature->IsHostileTo(who) && who->isInAccessablePlaceFor(m_creature)) m_creature->IsHostileTo(who) && who->IsInAccessablePlaceFor(m_creature))
{ {
if (!m_creature->CanFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) if (!m_creature->CanFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
return; return;
@ -1271,10 +1295,10 @@ void CreatureEventAI::MoveInLineOfSight(Unit* who)
void CreatureEventAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell) void CreatureEventAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell)
{ {
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
if ((*i).Event.event_type == EVENT_T_SPELLHIT) if (i->Event.event_type == EVENT_T_SPELLHIT)
// If spell id matches (or no spell id) & if spell school matches (or no spell school) // If spell id matches (or no spell id) & if spell school matches (or no spell school)
if (!(*i).Event.spell_hit.spellId || pSpell->Id == (*i).Event.spell_hit.spellId) if (!i->Event.spell_hit.spellId || pSpell->Id == i->Event.spell_hit.spellId)
if (pSpell->SchoolMask & (*i).Event.spell_hit.schoolMask) if (pSpell->SchoolMask & i->Event.spell_hit.schoolMask)
ProcessEvent(*i, pUnit); ProcessEvent(*i, pUnit);
} }
@ -1292,55 +1316,28 @@ void CreatureEventAI::UpdateAI(const uint32 diff)
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
// Decrement Timers // Decrement Timers
if ((*i).Time) if (i->Time)
{ {
if ((*i).Time > m_EventDiff) if (i->Time > m_EventDiff)
{ {
// Do not decrement timers if event cannot trigger in this phase // Do not decrement timers if event cannot trigger in this phase
if (!((*i).Event.event_inverse_phase_mask & (1 << m_Phase))) if (!(i->Event.event_inverse_phase_mask & (1 << m_Phase)))
(*i).Time -= m_EventDiff; i->Time -= m_EventDiff;
// Skip processing of events that have time remaining
continue;
} }
else (*i).Time = 0; else
i->Time = 0;
} }
// Events that are updated every EVENT_UPDATE_TIME // Skip processing of events that have time remaining or are disabled
switch ((*i).Event.event_type) if (!(i->Enabled) || i->Time)
{ continue;
case EVENT_T_TIMER_OOC:
case EVENT_T_TIMER_GENERIC:
ProcessEvent(*i);
break;
case EVENT_T_TIMER_IN_COMBAT:
case EVENT_T_MANA:
case EVENT_T_HP:
case EVENT_T_TARGET_HP:
case EVENT_T_TARGET_CASTING:
case EVENT_T_FRIENDLY_HP:
case EVENT_T_AURA:
case EVENT_T_TARGET_AURA:
case EVENT_T_MISSING_AURA:
case EVENT_T_TARGET_MISSING_AURA:
if (Combat)
ProcessEvent(*i);
break;
case EVENT_T_RANGE:
if (Combat)
{
if (m_creature->getVictim() && m_creature->IsInMap(m_creature->getVictim()))
if (m_creature->IsInRange(m_creature->getVictim(), (float)(*i).Event.range.minDist, (float)(*i).Event.range.maxDist))
ProcessEvent(*i);
}
break;
default:
break;
}
m_EventDiff = 0; if (IsTimerBasedEvent(i->Event.event_type))
m_EventUpdateTime = EVENT_UPDATE_TIME; ProcessEvent(*i);
} }
m_EventDiff = 0;
m_EventUpdateTime = EVENT_UPDATE_TIME;
} }
else else
{ {
@ -1348,9 +1345,23 @@ void CreatureEventAI::UpdateAI(const uint32 diff)
m_EventUpdateTime -= diff; m_EventUpdateTime -= diff;
} }
// Melee Auto-Attack (recheck m_creature->getVictim in case of combat state was changed while processing events) // Melee Auto-Attack (getVictim might be nullptr as result of timer based events and actions)
if (Combat && m_MeleeEnabled && m_creature->getVictim()) if (Combat && m_creature->getVictim())
DoMeleeAttackIfReady(); {
// Update creature dynamic movement position before doing anything else
if (m_DynamicMovement)
{
if (!m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT) && !m_creature->IsNonMeleeSpellCasted(false))
{
if (m_LastSpellMaxRange && m_creature->IsInRange(m_creature->getVictim(), 0, (m_LastSpellMaxRange / 1.5f)))
SetCombatMovement(false, true);
else
SetCombatMovement(true, true);
}
}
else if (m_MeleeEnabled)
DoMeleeAttackIfReady();
}
} }
bool CreatureEventAI::IsVisible(Unit* pl) const bool CreatureEventAI::IsVisible(Unit* pl) const
@ -1478,12 +1489,12 @@ void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
{ {
for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr) for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr)
{ {
if ((*itr).Event.event_type == EVENT_T_RECEIVE_EMOTE) if (itr->Event.event_type == EVENT_T_RECEIVE_EMOTE)
{ {
if ((*itr).Event.receive_emote.emoteId != text_emote) if (itr->Event.receive_emote.emoteId != text_emote)
return; continue;
PlayerCondition pcon(0, (*itr).Event.receive_emote.condition, (*itr).Event.receive_emote.conditionValue1, (*itr).Event.receive_emote.conditionValue2); PlayerCondition pcon(0, itr->Event.receive_emote.condition, itr->Event.receive_emote.conditionValue1, itr->Event.receive_emote.conditionValue2);
if (pcon.Meets(pPlayer, m_creature->GetMap(), m_creature, CONDITION_FROM_EVENTAI)) if (pcon.Meets(pPlayer, m_creature->GetMap(), m_creature, CONDITION_FROM_EVENTAI))
{ {
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "CreatureEventAI: ReceiveEmote CreatureEventAI: Condition ok, processing"); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "CreatureEventAI: ReceiveEmote CreatureEventAI: Condition ok, processing");

View file

@ -70,6 +70,7 @@ enum EventAI_Type
EVENT_T_TARGET_MISSING_AURA = 28, // Param1 = SpellID, Param2 = Number of time stacked expected, Param3/4 Repeat Min/Max EVENT_T_TARGET_MISSING_AURA = 28, // Param1 = SpellID, Param2 = Number of time stacked expected, Param3/4 Repeat Min/Max
EVENT_T_TIMER_GENERIC = 29, // InitialMin, InitialMax, RepeatMin, RepeatMax EVENT_T_TIMER_GENERIC = 29, // InitialMin, InitialMax, RepeatMin, RepeatMax
EVENT_T_RECEIVE_AI_EVENT = 30, // AIEventType, Sender-Entry, unused, unused EVENT_T_RECEIVE_AI_EVENT = 30, // AIEventType, Sender-Entry, unused, unused
EVENT_T_ENERGY = 31, // EnergyMax%, EnergyMin%, RepeatMin, RepeatMax
EVENT_T_END, EVENT_T_END,
}; };
@ -467,6 +468,7 @@ struct CreatureEventAI_Event
// EVENT_T_MANA = 3 // EVENT_T_MANA = 3
// EVENT_T_TARGET_HP = 12 // EVENT_T_TARGET_HP = 12
// EVENT_T_TARGET_MANA = 18 // EVENT_T_TARGET_MANA = 18
// EVENT_T_ENERGY = 31
struct struct
{ {
uint32 percentMax; uint32 percentMax;

View file

@ -90,7 +90,7 @@ void CreatureEventAIMgr::CheckUnusedAITexts()
sLog.outErrorEventAI("Entry %i in table `creature_ai_texts` but not used in EventAI scripts.", *itr); sLog.outErrorEventAI("Entry %i in table `creature_ai_texts` but not used in EventAI scripts.", *itr);
} }
/// Helper function to check if a target-suite is suitable for the event-type /// Helper function to check if a target-type is suitable for the event-type
bool IsValidTargetType(EventAI_Type eventType, EventAI_ActionType actionType, uint32 targetType, uint32 eventId, uint8 action) bool IsValidTargetType(EventAI_Type eventType, EventAI_ActionType actionType, uint32 targetType, uint32 eventId, uint8 action)
{ {
switch (targetType) switch (targetType)
@ -327,6 +327,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
case EVENT_T_MANA: case EVENT_T_MANA:
case EVENT_T_TARGET_HP: case EVENT_T_TARGET_HP:
case EVENT_T_TARGET_MANA: case EVENT_T_TARGET_MANA:
case EVENT_T_ENERGY:
if (temp.percent_range.percentMax > 100) if (temp.percent_range.percentMax > 100)
sLog.outErrorEventAI("Creature %u are using percentage event(%u) with param2 (MinPercent) > 100. Event will never trigger! ", temp.creature_id, i); sLog.outErrorEventAI("Creature %u are using percentage event(%u) with param2 (MinPercent) > 100. Event will never trigger! ", temp.creature_id, i);

View file

@ -1269,8 +1269,11 @@ void GameObject::Use(Unit* user)
player->RewardPlayerAndGroupAtCast(this); player->RewardPlayerAndGroupAtCast(this);
} }
if (scriptReturnValue) // activate script
{ return; } if (!scriptReturnValue)
GetMap()->ScriptsStart(sGameObjectScripts, GetGUIDLow(), spellCaster, this);
else
return;
// cast this spell later if provided // cast this spell later if provided
spellId = info->goober.spellId; spellId = info->goober.spellId;
@ -2382,6 +2385,23 @@ void GameObject::ForceGameObjectHealth(int32 diff, Unit* caster)
SetGoAnimProgress(GetMaxHealth() ? m_useTimes * 255 / GetMaxHealth() : 255); SetGoAnimProgress(GetMaxHealth() ? m_useTimes * 255 / GetMaxHealth() : 255);
} }
float GameObject::GetInteractionDistance()
{
switch (GetGoType())
{
// TODO: find out how the client calculates the maximal usage distance to spellless working
// gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary chosen number
case GAMEOBJECT_TYPE_GUILD_BANK:
case GAMEOBJECT_TYPE_MAILBOX:
return 10.0f;
case GAMEOBJECT_TYPE_FISHINGHOLE:
case GAMEOBJECT_TYPE_FISHINGNODE:
return 20.0f + CONTACT_DISTANCE; // max spell range
default:
return INTERACTION_DISTANCE;
}
}
uint32 GameObject::GetScriptId() uint32 GameObject::GetScriptId()
{ {
return sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) ? sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) : sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, GetEntry()); return sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) ? sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) : sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, GetEntry());

View file

@ -842,6 +842,11 @@ class GameObject : public WorldObject
ObjectGuid m_lootRecipientGuid; // player who will have rights for looting if m_lootGroupRecipient==0 or group disbanded ObjectGuid m_lootRecipientGuid; // player who will have rights for looting if m_lootGroupRecipient==0 or group disbanded
uint32 m_lootGroupRecipientId; // group who will have rights for looting if set and exist uint32 m_lootGroupRecipientId; // group who will have rights for looting if set and exist
// Used for chest type
bool m_isInUse; // only one player at time are allowed to open chest
time_t m_reStockTimer; // timer to refill the chest
time_t m_despawnTimer; // timer to despawn the chest if something changed in it
private: private:
void SwitchDoorOrButton(bool activate, bool alternative = false); void SwitchDoorOrButton(bool activate, bool alternative = false);
void TickCapturePoint(); void TickCapturePoint();

View file

@ -48,7 +48,7 @@ void GuardAI::MoveInLineOfSight(Unit* u)
if (!m_creature->getVictim() && u->IsTargetableForAttack() && if (!m_creature->getVictim() && u->IsTargetableForAttack() &&
(u->IsHostileToPlayers() || m_creature->IsHostileTo(u) /*|| u->getVictim() && m_creature->IsFriendlyTo(u->getVictim())*/) && (u->IsHostileToPlayers() || m_creature->IsHostileTo(u) /*|| u->getVictim() && m_creature->IsFriendlyTo(u->getVictim())*/) &&
u->isInAccessablePlaceFor(m_creature)) u->IsInAccessablePlaceFor(m_creature))
{ {
float attackRadius = m_creature->GetAttackDistance(u); float attackRadius = m_creature->GetAttackDistance(u);
if (m_creature->IsWithinDistInMap(u, attackRadius)) if (m_creature->IsWithinDistInMap(u, attackRadius))

View file

@ -332,7 +332,7 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
return false; return false;
} }
if (maxcount < mincountOrRef) // wrong max count if (maxcount < (uint32)mincountOrRef) // wrong max count
{ {
sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, uint32(maxcount), mincountOrRef); sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, uint32(maxcount), mincountOrRef);
return false; return false;

View file

@ -70,7 +70,9 @@ enum LootType
LOOT_FISHINGHOLE = 20, // unsupported by client, sending LOOT_FISHING instead LOOT_FISHINGHOLE = 20, // unsupported by client, sending LOOT_FISHING instead
LOOT_FISHING_FAIL = 21, // unsupported by client, sending LOOT_FISHING instead LOOT_FISHING_FAIL = 21, // unsupported by client, sending LOOT_FISHING instead
LOOT_INSIGNIA = 22 // unsupported by client, sending LOOT_CORPSE instead LOOT_INSIGNIA = 22, // unsupported by client, sending LOOT_CORPSE instead
LOOT_MAIL = 23,
LOOT_SPELL = 24,
}; };
enum LootSlotType enum LootSlotType

View file

@ -664,19 +664,37 @@ void Object::BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, UpdateMask* u
{ {
*data << (m_uint32Values[index] & ~UNIT_FLAG_NOT_SELECTABLE); *data << (m_uint32Values[index] & ~UNIT_FLAG_NOT_SELECTABLE);
} }
// hide lootable animation for unallowed players /* Hide loot animation for players that aren't permitted to loot the corpse */
else if (index == UNIT_DYNAMIC_FLAGS && GetTypeId() == TYPEID_UNIT) else if (index == UNIT_DYNAMIC_FLAGS && GetTypeId() == TYPEID_UNIT)
{ {
uint32 send_value = m_uint32Values[index];
/* Initiate pointer to creature so we can check loot */
if (Creature* my_creature = (Creature*)this)
/* If the creature is NOT fully looted */
if (!my_creature->loot.isLooted())
/* If the lootable flag is NOT set */
if (!(send_value & UNIT_DYNFLAG_LOOTABLE))
{
/* Update it on the creature */
my_creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
/* Update it in the packet */
send_value = send_value | UNIT_DYNFLAG_LOOTABLE;
}
/* If we're not allowed to loot the target, destroy the lootable flag */
if (!target->isAllowedToLoot((Creature*)this)) if (!target->isAllowedToLoot((Creature*)this))
*data << (m_uint32Values[index] & ~(UNIT_DYNFLAG_LOOTABLE | UNIT_DYNFLAG_TAPPED_BY_PLAYER)); if (send_value & UNIT_DYNFLAG_LOOTABLE)
else { send_value = send_value & ~UNIT_DYNFLAG_LOOTABLE; }
{
// flag only for original loot recipent /* If we are allowed to loot it and mob is tapped by us, destroy the tapped flag */
if (target->GetObjectGuid() == ((Creature*)this)->GetLootRecipientGuid()) bool is_tapped = target->IsTappedByMeOrMyGroup((Creature*)this);
*data << m_uint32Values[index];
else /* If the creature has tapped flag but is tapped by us, remove the flag */
*data << (m_uint32Values[index] & ~(UNIT_DYNFLAG_TAPPED | UNIT_DYNFLAG_TAPPED_BY_PLAYER)); if (send_value & UNIT_DYNFLAG_TAPPED && is_tapped)
} { send_value = send_value & ~UNIT_DYNFLAG_TAPPED; }
*data << send_value;
} }
else else
{ {
@ -1479,8 +1497,11 @@ void WorldObject::UpdateGroundPositionZ(float x, float y, float& z) const
{ z = new_z + 0.05f; } // just to be sure that we are not a few pixel under the surface { z = new_z + 0.05f; } // just to be sure that we are not a few pixel under the surface
} }
void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z) const void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z, Map* atMap /*=nullptr*/) const
{ {
if (!atMap)
atMap = GetMap();
switch (GetTypeId()) switch (GetTypeId())
{ {
case TYPEID_UNIT: case TYPEID_UNIT:
@ -1492,21 +1513,21 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z) const
bool canSwim = ((Creature const*)this)->CanSwim(); bool canSwim = ((Creature const*)this)->CanSwim();
float ground_z = z; float ground_z = z;
float max_z = canSwim float max_z = canSwim
? GetTerrain()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)) ? atMap->GetTerrain()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK))
: ((ground_z = GetMap()->GetHeight(GetPhaseMask(), x, y, z))); : ((ground_z = atMap->GetHeight(GetPhaseMask(), x, y, z)));
if (max_z > INVALID_HEIGHT) if (max_z > INVALID_HEIGHT)
{ {
if (z > max_z) if (z > max_z)
{ z = max_z; } z = max_z;
else if (z < ground_z) else if (z < ground_z)
{ z = ground_z; } z = ground_z;
} }
} }
else else
{ {
float ground_z = GetMap()->GetHeight(GetPhaseMask(), x, y, z); float ground_z = atMap->GetHeight(GetPhaseMask(), x, y, z);
if (z < ground_z) if (z < ground_z)
{ z = ground_z; } z = ground_z;
} }
break; break;
} }
@ -1516,18 +1537,18 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z) const
if (!((Player const*)this)->CanFly()) if (!((Player const*)this)->CanFly())
{ {
float ground_z = z; float ground_z = z;
float max_z = GetTerrain()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)); float max_z = atMap->GetTerrain()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK));
if (max_z > INVALID_HEIGHT) if (max_z > INVALID_HEIGHT)
{ {
if (z > max_z) if (z > max_z)
{ z = max_z; } z = max_z;
else if (z < ground_z) else if (z < ground_z)
{ z = ground_z; } z = ground_z;
} }
} }
else else
{ {
float ground_z = GetMap()->GetHeight(GetPhaseMask(), x, y, z); float ground_z = atMap->GetHeight(GetPhaseMask(), x, y, z);
if (z < ground_z) if (z < ground_z)
z = ground_z; z = ground_z;
} }
@ -1535,9 +1556,9 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z) const
} }
default: default:
{ {
float ground_z = GetMap()->GetHeight(GetPhaseMask(), x, y, z); float ground_z = atMap->GetHeight(GetPhaseMask(), x, y, z);
if (ground_z > INVALID_HEIGHT) if (ground_z > INVALID_HEIGHT)
{ z = ground_z; } z = ground_z;
break; break;
} }
} }
@ -1914,9 +1935,9 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
if (!sWorld.getConfig(CONFIG_BOOL_DETECT_POS_COLLISION)) if (!sWorld.getConfig(CONFIG_BOOL_DETECT_POS_COLLISION))
{ {
if (searcher) if (searcher)
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available searcher->UpdateAllowedPositionZ(x, y, z, GetMap()); // update to LOS height if available
else else
{ UpdateGroundPositionZ(x, y, z); } UpdateGroundPositionZ(x, y, z);
return; return;
} }
@ -1942,12 +1963,12 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
if (selector.CheckOriginalAngle()) if (selector.CheckOriginalAngle())
{ {
if (searcher) if (searcher)
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available searcher->UpdateAllowedPositionZ(x, y, z, GetMap()); // update to LOS height if available
else else
{ UpdateGroundPositionZ(x, y, z); } UpdateGroundPositionZ(x, y, z);
if (fabs(init_z - z) < dist && IsWithinLOS(x, y, z)) if (fabs(init_z - z) < dist && IsWithinLOS(x, y, z))
{ return; } return;
first_los_conflict = true; // first point have LOS problems first_los_conflict = true; // first point have LOS problems
} }
@ -1964,12 +1985,12 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
z = GetPositionZ(); z = GetPositionZ();
if (searcher) if (searcher)
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available searcher->UpdateAllowedPositionZ(x, y, z, GetMap()); // update to LOS height if available
else else
{ UpdateGroundPositionZ(x, y, z); } UpdateGroundPositionZ(x, y, z);
if (fabs(init_z - z) < dist && IsWithinLOS(x, y, z)) if (fabs(init_z - z) < dist && IsWithinLOS(x, y, z))
{ return; } return;
} }
// BAD NEWS: not free pos (or used or have LOS problems) // BAD NEWS: not free pos (or used or have LOS problems)
@ -1980,9 +2001,9 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
y = first_y; y = first_y;
if (searcher) if (searcher)
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available searcher->UpdateAllowedPositionZ(x, y, z, GetMap()); // update to LOS height if available
else else
{ UpdateGroundPositionZ(x, y, z); } UpdateGroundPositionZ(x, y, z);
return; return;
} }
@ -1996,12 +2017,12 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
z = GetPositionZ(); z = GetPositionZ();
if (searcher) if (searcher)
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available searcher->UpdateAllowedPositionZ(x, y, z, GetMap()); // update to LOS height if available
else else
{ UpdateGroundPositionZ(x, y, z); } UpdateGroundPositionZ(x, y, z);
if (fabs(init_z - z) < dist && IsWithinLOS(x, y, z)) if (fabs(init_z - z) < dist && IsWithinLOS(x, y, z))
{ return; } return;
} }
// BAD BAD NEWS: all found pos (free and used) have LOS problem :( // BAD BAD NEWS: all found pos (free and used) have LOS problem :(
@ -2009,9 +2030,9 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
y = first_y; y = first_y;
if (searcher) if (searcher)
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available searcher->UpdateAllowedPositionZ(x, y, z, GetMap());// update to LOS height if available
else else
{ UpdateGroundPositionZ(x, y, z); } UpdateGroundPositionZ(x, y, z);
} }
void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update)

View file

@ -536,7 +536,7 @@ class WorldObject : public Object
bool IsPositionValid() const; bool IsPositionValid() const;
void UpdateGroundPositionZ(float x, float y, float& z) const; void UpdateGroundPositionZ(float x, float y, float& z) const;
void UpdateAllowedPositionZ(float x, float y, float& z) const; void UpdateAllowedPositionZ(float x, float y, float& z, Map* atMap = nullptr) const;
void GetRandomPoint(float x, float y, float z, float distance, float& rand_x, float& rand_y, float& rand_z) const; void GetRandomPoint(float x, float y, float z, float distance, float& rand_x, float& rand_y, float& rand_z) const;

View file

@ -1438,7 +1438,7 @@ void ObjectMgr::LoadCreatures()
if (cInfo->RegenerateStats & REGEN_FLAG_HEALTH && data.curhealth < cInfo->MinLevelHealth) if (cInfo->RegenerateStats & REGEN_FLAG_HEALTH && data.curhealth < cInfo->MinLevelHealth)
{ {
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`MinLevelHealth`=%u.", guid, data.id, data.curhealth, cInfo->MinLevelHealth); sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenerateStats` & REGEN_FLAG_HEALTH and low current health (%u), `creature_template`.`MinLevelHealth`=%u.", guid, data.id, data.curhealth, cInfo->MinLevelHealth);
data.curhealth = cInfo->MinLevelHealth; data.curhealth = cInfo->MinLevelHealth;
} }
@ -1491,8 +1491,13 @@ void ObjectMgr::LoadCreatures()
} }
if (gameEvent == 0 && GuidPoolId == 0 && EntryPoolId == 0) // if not this is to be managed by GameEvent System or Pool system if (gameEvent == 0 && GuidPoolId == 0 && EntryPoolId == 0) // if not this is to be managed by GameEvent System or Pool system
{
AddCreatureToGrid(guid, &data); AddCreatureToGrid(guid, &data);
if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_ACTIVE)
m_activeCreatures.insert(ActiveCreatureGuidsOnMap::value_type(data.mapid, guid));
}
++count; ++count;
} }
while (result->NextRow()); while (result->NextRow());
@ -7580,9 +7585,9 @@ void ObjectMgr::LoadCreatureQuestRelations()
{ {
CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
if (!cInfo) if (!cInfo)
sLog.outErrorDb("Table `creature_questrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second); sLog.outErrorDb("Table `creature_involvedrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second);
else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER)) else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER))
sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but NpcFlags does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second); sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but NpcFlags does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second);
} }
} }
@ -9400,6 +9405,7 @@ void ObjectMgr::LoadTrainerTemplates()
// post loading check // post loading check
std::set<uint32> trainer_ids; std::set<uint32> trainer_ids;
bool hasErrored = false;
for (CacheTrainerSpellMap::const_iterator tItr = m_mCacheTrainerTemplateSpellMap.begin(); tItr != m_mCacheTrainerTemplateSpellMap.end(); ++tItr) for (CacheTrainerSpellMap::const_iterator tItr = m_mCacheTrainerTemplateSpellMap.begin(); tItr != m_mCacheTrainerTemplateSpellMap.end(); ++tItr)
trainer_ids.insert(tItr->first); trainer_ids.insert(tItr->first);
@ -9408,18 +9414,21 @@ void ObjectMgr::LoadTrainerTemplates()
{ {
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i)) if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{ {
if (cInfo->TrainerTemplateId)
{
if (m_mCacheTrainerTemplateSpellMap.find(cInfo->TrainerTemplateId) != m_mCacheTrainerTemplateSpellMap.end()) if (m_mCacheTrainerTemplateSpellMap.find(cInfo->TrainerTemplateId) != m_mCacheTrainerTemplateSpellMap.end())
trainer_ids.erase(cInfo->TrainerTemplateId); trainer_ids.erase(cInfo->TrainerTemplateId);
else else
sLog.outErrorDb("Creature (Entry: %u) has trainer_id = %u for nonexistent trainer template", cInfo->Entry, cInfo->TrainerTemplateId); {
} sLog.outErrorDb("Creature (Entry: %u) has TrainerTemplateId = %u for nonexistent trainer template", cInfo->Entry, cInfo->TrainerTemplateId);
hasErrored = true;
}
} }
} }
for (std::set<uint32>::const_iterator tItr = trainer_ids.begin(); tItr != trainer_ids.end(); ++tItr) for (std::set<uint32>::const_iterator tItr = trainer_ids.begin(); tItr != trainer_ids.end(); ++tItr)
sLog.outErrorDb("Table `npc_trainer_template` has trainer template %u not used by any trainers ", *tItr); sLog.outErrorDb("Table `npc_trainer_template` has trainer template %u not used by any trainers ", *tItr);
if (hasErrored || !trainer_ids.empty()) // Append extra line in case of reported errors
sLog.outString();
} }
void ObjectMgr::LoadVendors(char const* tableName, bool isTemplates) void ObjectMgr::LoadVendors(char const* tableName, bool isTemplates)
@ -9497,7 +9506,7 @@ void ObjectMgr::LoadVendorTemplates()
if (m_mCacheVendorTemplateItemMap.find(cInfo->VendorTemplateId) != m_mCacheVendorTemplateItemMap.end()) if (m_mCacheVendorTemplateItemMap.find(cInfo->VendorTemplateId) != m_mCacheVendorTemplateItemMap.end())
vendor_ids.erase(cInfo->VendorTemplateId); vendor_ids.erase(cInfo->VendorTemplateId);
else else
sLog.outErrorDb("Creature (Entry: %u) has vendor_id = %u for nonexistent vendor template", cInfo->Entry, cInfo->VendorTemplateId); sLog.outErrorDb("Creature (Entry: %u) has VendorTemplateId = %u for nonexistent vendor template", cInfo->Entry, cInfo->VendorTemplateId);
} }
} }
} }
@ -9506,6 +9515,56 @@ void ObjectMgr::LoadVendorTemplates()
sLog.outErrorDb("Table `npc_vendor_template` has vendor template %u not used by any vendors ", *vItr); sLog.outErrorDb("Table `npc_vendor_template` has vendor template %u not used by any vendors ", *vItr);
} }
/* This function is supposed to take care of three things:
* 1) Load Transports on Map or on Continents
* 2) Load Active Npcs on Map or Continents
* 3) Load Everything dependend on config setting LoadAllGridsOnMaps
*
* This function is currently WIP, hence parts exist only as draft.
*/
void ObjectMgr::LoadActiveEntities(Map* _map)
{
// Special case on startup - load continents
if (!_map)
{
uint32 continents[] = {0, 1, 530, 571};
for (int i = 0; i < countof(continents); ++i)
{
_map = sMapMgr.FindMap(continents[i]);
if (!_map)
_map = sMapMgr.CreateMap(continents[i], nullptr);
if (_map)
LoadActiveEntities(_map);
else
sLog.outError("ObjectMgr::LoadActiveEntities - Unable to create Map %u", continents[i]);
}
return;
}
// Load active objects for _map
if (sWorld.isForceLoadMap(_map->GetId()))
{
for (CreatureDataMap::const_iterator itr = mCreatureDataMap.begin(); itr != mCreatureDataMap.end(); ++itr)
{
if (itr->second.mapid == _map->GetId())
_map->ForceLoadGrid(itr->second.posX, itr->second.posY);
}
}
else // Normal case - Load all npcs that are active
{
std::pair<ActiveCreatureGuidsOnMap::const_iterator, ActiveCreatureGuidsOnMap::const_iterator> bounds = m_activeCreatures.equal_range(_map->GetId());
for (ActiveCreatureGuidsOnMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
{
CreatureData const& data = mCreatureDataMap[itr->second];
_map->ForceLoadGrid(data.posX, data.posY);
}
}
// Load Transports on Map _map
}
void ObjectMgr::LoadNpcGossips() void ObjectMgr::LoadNpcGossips()
{ {
m_mCacheNpcTextIdMap.clear(); m_mCacheNpcTextIdMap.clear();
@ -9568,11 +9627,9 @@ void ObjectMgr::LoadGossipMenu(std::set<uint32>& gossipScriptSet)
if (!result) if (!result)
{ {
BarGoLink bar(1); BarGoLink bar(1);
bar.step(); bar.step();
sLog.outString();
sLog.outErrorDb(">> Loaded gossip_menu, table is empty!"); sLog.outErrorDb(">> Loaded gossip_menu, table is empty!");
sLog.outString();
return; return;
} }
@ -9631,20 +9688,25 @@ void ObjectMgr::LoadGossipMenu(std::set<uint32>& gossipScriptSet)
delete result; delete result;
sLog.outString();
sLog.outString(">> Loaded %u gossip_menu entries", count);
// post loading tests // post loading tests
for (uint32 i = 1; i < sCreatureStorage.GetMaxEntry(); ++i) for (uint32 i = 1; i < sCreatureStorage.GetMaxEntry(); ++i)
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i)) if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
if (cInfo->GossipMenuId) if (cInfo->GossipMenuId)
if (m_mGossipMenusMap.find(cInfo->GossipMenuId) == m_mGossipMenusMap.end()) if (m_mGossipMenusMap.find(cInfo->GossipMenuId) == m_mGossipMenusMap.end())
sLog.outErrorDb("Creature (Entry: %u) has gossip_menu_id = %u for nonexistent menu", cInfo->Entry, cInfo->GossipMenuId); sLog.outErrorDb("Creature (Entry: %u) has GossipMenuId = %u for nonexistent menu", cInfo->Entry, cInfo->GossipMenuId);
}
for (SQLStorageBase::SQLSIterator<GameObjectInfo> itr = sGOStorage.getDataBegin<GameObjectInfo>(); itr < sGOStorage.getDataEnd<GameObjectInfo>(); ++itr) if (!sLog.HasLogFilter(LOG_FILTER_DB_STRICTED_CHECK))
if (uint32 menuid = itr->GetGossipMenuId()) {
if (m_mGossipMenusMap.find(menuid) == m_mGossipMenusMap.end()) for (SQLStorageBase::SQLSIterator<GameObjectInfo> itr = sGOStorage.getDataBegin<GameObjectInfo>(); itr < sGOStorage.getDataEnd<GameObjectInfo>(); ++itr)
ERROR_DB_STRICT_LOG("Gameobject (Entry: %u) has gossip_menu_id = %u for nonexistent menu", itr->id, menuid); if (uint32 menuid = itr->GetGossipMenuId())
if (m_mGossipMenusMap.find(menuid) == m_mGossipMenusMap.end())
sLog.outErrorDb("Gameobject (Entry: %u) has gossip_menu_id = %u for nonexistent menu", itr->id, menuid);
}
sLog.outString(">> Loaded %u gossip_menu entries", count);
sLog.outString();
} }
void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet) void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
@ -9660,11 +9722,9 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
if (!result) if (!result)
{ {
BarGoLink bar(1); BarGoLink bar(1);
bar.step(); bar.step();
sLog.outString();
sLog.outErrorDb(">> Loaded gossip_menu_option, table is empty!"); sLog.outErrorDb(">> Loaded gossip_menu_option, table is empty!");
sLog.outString();
return; return;
} }
@ -9770,7 +9830,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
} }
if (found_menu_uses && !found_flags_uses) if (found_menu_uses && !found_flags_uses)
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has `npc_option_NpcFlags` = %u but creatures using this menu does not have corresponding`NpcFlags`. Option will not accessible in game.", gMenuItem.menu_id, gMenuItem.id, gMenuItem.npc_option_NpcFlags); sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has `npc_option_npcflag` = %u but creatures using this menu does not have corresponding `NpcFlags`. Option will not accessible in game.", gMenuItem.menu_id, gMenuItem.id, gMenuItem.npc_option_NpcFlags);
} }
if (gMenuItem.action_poi_id && !GetPointOfInterest(gMenuItem.action_poi_id)) if (gMenuItem.action_poi_id && !GetPointOfInterest(gMenuItem.action_poi_id))
@ -9804,7 +9864,6 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
m_mGossipMenuItemsMap.insert(GossipMenuItemsMap::value_type(gMenuItem.menu_id, gMenuItem)); m_mGossipMenuItemsMap.insert(GossipMenuItemsMap::value_type(gMenuItem.menu_id, gMenuItem));
++count; ++count;
} }
while (result->NextRow()); while (result->NextRow());
@ -9816,8 +9875,8 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
sLog.outErrorDb("Table `gossip_menu` contain unused (in creature or GO or menu options) menu id %u.", *itr); sLog.outErrorDb("Table `gossip_menu` contain unused (in creature or GO or menu options) menu id %u.", *itr);
} }
sLog.outString();
sLog.outString(">> Loaded %u gossip_menu_option entries", count); sLog.outString(">> Loaded %u gossip_menu_option entries", count);
sLog.outString();
} }
void ObjectMgr::LoadGossipMenus() void ObjectMgr::LoadGossipMenus()

View file

@ -831,6 +831,9 @@ class ObjectMgr
void LoadTrainerTemplates(); void LoadTrainerTemplates();
void LoadTrainers() { LoadTrainers("npc_trainer", false); } void LoadTrainers() { LoadTrainers("npc_trainer", false); }
/// @param _map Map* of the map for which to load active entities. If nullptr active entities on continents are loaded
void LoadActiveEntities(Map* _map);
void LoadVehicleAccessory(); void LoadVehicleAccessory();
std::string GeneratePetName(uint32 entry); std::string GeneratePetName(uint32 entry);
@ -1340,10 +1343,13 @@ class ObjectMgr
HalfNameMap PetHalfName0; HalfNameMap PetHalfName0;
HalfNameMap PetHalfName1; HalfNameMap PetHalfName1;
typedef std::multimap<uint32 /*mapId*/, uint32 /*guid*/> ActiveCreatureGuidsOnMap;
// Array to store creature stats, Max creature level + 1 (for data alignement with in game level) // Array to store creature stats, Max creature level + 1 (for data alignement with in game level)
CreatureClassLvlStats m_creatureClassLvlStats[DEFAULT_MAX_CREATURE_LEVEL + 1][MAX_CREATURE_CLASS][MAX_EXPANSION + 1]; CreatureClassLvlStats m_creatureClassLvlStats[DEFAULT_MAX_CREATURE_LEVEL + 1][MAX_CREATURE_CLASS][MAX_EXPANSION + 1];
MapObjectGuids mMapObjectGuids; MapObjectGuids mMapObjectGuids;
ActiveCreatureGuidsOnMap m_activeCreatures;
CreatureDataMap mCreatureDataMap; CreatureDataMap mCreatureDataMap;
CreatureLocaleMap mCreatureLocaleMap; CreatureLocaleMap mCreatureLocaleMap;
GameObjectDataMap mGameObjectDataMap; GameObjectDataMap mGameObjectDataMap;

View file

@ -504,6 +504,7 @@ void Pet::SetDeathState(DeathState s) // overwrite virtual
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
CastPetAuras(true); CastPetAuras(true);
} }
CastOwnerTalentAuras();
} }
void Pet::Update(uint32 update_diff, uint32 diff) void Pet::Update(uint32 update_diff, uint32 diff)
@ -2091,6 +2092,40 @@ void Pet::SynchronizeLevelWithOwner()
} }
} }
void Pet::SetModeFlags(PetModeFlags mode)
{
m_petModeFlags = mode;
Unit* owner = GetOwner();
if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
return;
WorldPacket data(SMSG_PET_MODE, 12);
data << GetObjectGuid();
data << uint32(m_petModeFlags);
((Player*)owner)->GetSession()->SendPacket(&data);
}
void Pet::SetStayPosition(bool stay)
{
if (stay)
{
m_stayPosX = GetPositionX();
m_stayPosY = GetPositionY();
m_stayPosZ = GetPositionZ();
m_stayPosO = GetOrientation();
}
else
{
m_stayPosX = 0;
m_stayPosY = 0;
m_stayPosZ = 0;
m_stayPosO = 0;
}
m_stayPosSet = stay;
}
void Pet::ApplyModeFlags(PetModeFlags mode, bool apply) void Pet::ApplyModeFlags(PetModeFlags mode, bool apply)
{ {
if (apply) if (apply)

View file

@ -206,6 +206,7 @@ class Pet : public Creature
bool CanTakeMoreActiveSpells(uint32 SpellIconID); bool CanTakeMoreActiveSpells(uint32 SpellIconID);
void ToggleAutocast(uint32 spellid, bool apply); void ToggleAutocast(uint32 spellid, bool apply);
void SetModeFlags(PetModeFlags mode);
void ApplyModeFlags(PetModeFlags mode, bool apply); void ApplyModeFlags(PetModeFlags mode, bool apply);
PetModeFlags GetModeFlags() const { return m_petModeFlags; } PetModeFlags GetModeFlags() const { return m_petModeFlags; }
@ -231,6 +232,25 @@ class Pet : public Creature
bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
void CleanupActionBar(); void CleanupActionBar();
bool m_retreating;
void SetIsRetreating(bool retreating = false) { m_retreating = retreating; }
bool GetIsRetreating() { return m_retreating; }
bool m_stayPosSet;
float m_stayPosX;
float m_stayPosY;
float m_stayPosZ;
float m_stayPosO;
void SetStayPosition(bool stay = false);
bool IsStayPosSet() { return m_stayPosSet; }
float GetStayPosX() { return m_stayPosX; }
float GetStayPosY() { return m_stayPosY; }
float GetStayPosZ() { return m_stayPosZ; }
float GetStayPosO() { return m_stayPosO; }
PetSpellMap m_spells; PetSpellMap m_spells;
AutoSpellList m_autospells; AutoSpellList m_autospells;

View file

@ -60,7 +60,7 @@ void PetAI::MoveInLineOfSight(Unit* u)
return; return;
if (u->IsTargetableForAttack() && m_creature->IsHostileTo(u) && if (u->IsTargetableForAttack() && m_creature->IsHostileTo(u) &&
u->isInAccessablePlaceFor(m_creature)) u->IsInAccessablePlaceFor(m_creature))
{ {
float attackRadius = m_creature->GetAttackDistance(u); float attackRadius = m_creature->GetAttackDistance(u);
if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->GetDistanceZ(u) <= CREATURE_Z_ATTACK_RANGE) if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->GetDistanceZ(u) <= CREATURE_Z_ATTACK_RANGE)

View file

@ -346,6 +346,12 @@ void TradeData::SetMoney(uint64 money)
if (m_money == money) if (m_money == money)
return; return;
if (money > m_player->GetMoney())
{
m_player->GetSession()->SendTradeStatus(TRADE_STATUS_CLOSE_WINDOW);
return;
}
m_money = money; m_money = money;
SetAccepted(false); SetAccepted(false);
@ -1264,19 +1270,17 @@ void Player::Update(uint32 update_diff, uint32 p_time)
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
} }
} }
} }// Speed collect rest bonus (section/in hour)
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING)) if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))
{ {
if (roll_chance_i(3) && GetTimeInnEnter() > 0) // Freeze update if (GetTimeInnEnter() > 0) // Freeze update
{ {
time_t time_inn = time(NULL) - GetTimeInnEnter(); time_t time_inn = now - GetTimeInnEnter();
if (time_inn >= 10) // Freeze update if (time_inn >= 10) // Freeze update
{ {
float bubble = 0.125f * sWorld.getConfig(CONFIG_FLOAT_RATE_REST_INGAME); SetRestBonus(GetRestBonus() + ComputeRest(time_inn));
// Speed collect rest bonus (section/in hour) UpdateInnerTime(now);
SetRestBonus(float(GetRestBonus() + time_inn * (GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 72000) * bubble));
UpdateInnerTime(time(NULL));
} }
} }
} }
@ -2888,7 +2892,7 @@ void Player::InitStatsForLevel(bool reapplyMods)
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK | PLAYER_FLAGS_DND | PLAYER_FLAGS_GM | PLAYER_FLAGS_GHOST); RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK | PLAYER_FLAGS_DND | PLAYER_FLAGS_GM | PLAYER_FLAGS_GHOST);
RemoveStandFlags(UNIT_STAND_FLAGS_ALL); // one form stealth modified bytes RemoveStandFlags(UNIT_STAND_FLAGS_ALL); // one form stealth modified bytes
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP | UNIT_BYTE2_FLAG_SANCTUARY); RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP | UNIT_BYTE2_FLAG_SUPPORTABLE);
// restore if need some important flags // restore if need some important flags
SetUInt32Value(PLAYER_FIELD_BYTES2, 0); // flags empty by default SetUInt32Value(PLAYER_FIELD_BYTES2, 0); // flags empty by default
@ -4147,14 +4151,14 @@ void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
{ {
for (int i = 0; i < EQUIPMENT_SLOT_END; ++i) for (int i = 0; i < EQUIPMENT_SLOT_END; ++i)
{ {
if (m_items[i] == NULL) if (m_items[i] == nullptr)
continue; continue;
m_items[i]->BuildCreateUpdateBlockForPlayer(data, target); m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
} }
for (int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) for (int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
{ {
if (m_items[i] == NULL) if (m_items[i] == nullptr)
continue; continue;
m_items[i]->BuildCreateUpdateBlockForPlayer(data, target); m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
@ -4555,6 +4559,38 @@ void Player::SetWaterWalk(bool enable)
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
} }
void Player::SetLevitate(bool enable)
{
WorldPacket data;
BuildMoveLevitatePacket(&data, enable, 0);
GetSession()->SendPacket(&data);
}
void Player::SetCanFly(bool enable)
{
WorldPacket data;
BuildMoveSetCanFlyPacket(&data, enable, 0);
GetSession()->SendPacket(&data);
}
void Player::SetFeatherFall(bool enable)
{
WorldPacket data;
BuildMoveFeatherFallPacket(&data, enable, 0);
SendMessageToSet(&data, true);
// start fall from current height
if (!enable)
SetFallInformation(0, GetPositionZ());
}
void Player::SetHover(bool enable)
{
WorldPacket data;
BuildMoveHoverPacket(&data, enable, 0);
GetSession()->SendPacket(&data);
}
/* Preconditions: /* Preconditions:
- a resurrectable corpse must not be loaded for the player (only bones) - a resurrectable corpse must not be loaded for the player (only bones)
- the player must be in world - the player must be in world
@ -6184,9 +6220,6 @@ bool Player::SetPosition(float x, float y, float z, float orientation, bool tele
// group update // group update
if (GetGroup() && (old_x != x || old_y != y)) if (GetGroup() && (old_x != x || old_y != y))
SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION); SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION);
if (GetTrader() && !IsWithinDistInMap(GetTrader(), INTERACTION_DISTANCE))
GetSession()->SendCancelTrade(); // will close both side trade windows
} }
if (m_positionStatusUpdateTimer) // Update position's state only on interval if (m_positionStatusUpdateTimer) // Update position's state only on interval
@ -6966,13 +6999,13 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
if (zone->flags & AREA_FLAG_SANCTUARY) // in sanctuary if (zone->flags & AREA_FLAG_SANCTUARY) // in sanctuary
{ {
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE);
if (sWorld.IsFFAPvPRealm()) if (sWorld.IsFFAPvPRealm())
SetFFAPvP(false); SetFFAPvP(false);
} }
else else
{ {
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE);
} }
if (zone->flags & AREA_FLAG_CAPITAL) // in capital city if (zone->flags & AREA_FLAG_CAPITAL) // in capital city
@ -7483,9 +7516,9 @@ void Player::ApplyItemEquipSpell(Item* item, bool apply, bool form_change)
else else
{ {
// at un-apply remove all spells (not only at-apply, so any at-use active affects from item and etc) // at un-apply remove all spells (not only at-apply, so any at-use active affects from item and etc)
// except with at-use with negative charges, so allow consuming item spells (including with extra flag that prevent consume really) // except on form change and with at-use with negative charges, so allow consuming item spells (including with extra flag that prevent consume really)
// applied to player after item remove from equip slot // applied to player after item remove from equip slot
if (spellData.SpellTrigger == ITEM_SPELLTRIGGER_ON_USE && spellData.SpellCharges < 0) if (spellData.SpellTrigger == ITEM_SPELLTRIGGER_ON_USE && (form_change || spellData.SpellCharges < 0))
continue; continue;
} }
@ -14004,6 +14037,10 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const
return true; return true;
// each-from-all exclusive group ( < 0) // each-from-all exclusive group ( < 0)
// given a group with 2+ quests, and one of those has a branch that is not restricted by the group, return true
if (qInfo->GetPrevQuestId() != 0 && qPrevInfo->GetNextQuestId() != qInfo->GetPrevQuestId())
return true;
// can be start if only all quests in prev quest exclusive group completed and rewarded // can be start if only all quests in prev quest exclusive group completed and rewarded
ExclusiveQuestGroupsMapBounds bounds = sObjectMgr.GetExclusiveQuestGroupsMapBounds(qPrevInfo->GetExclusiveGroup()); ExclusiveQuestGroupsMapBounds bounds = sObjectMgr.GetExclusiveQuestGroupsMapBounds(qPrevInfo->GetExclusiveGroup());
@ -14037,6 +14074,11 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const
if (qPrevInfo->GetExclusiveGroup() >= 0) if (qPrevInfo->GetExclusiveGroup() >= 0)
return true; return true;
// each-from-all exclusive group ( < 0)
// given a group with 2+ quests, and one of those has a branch that is not restricted by the group, return true
if (qInfo->GetPrevQuestId() != 0 && qPrevInfo->GetNextQuestId() != abs(qInfo->GetPrevQuestId()))
return true;
// each-from-all exclusive group ( < 0) // each-from-all exclusive group ( < 0)
// can be start if only all quests in prev quest exclusive group active // can be start if only all quests in prev quest exclusive group active
ExclusiveQuestGroupsMapBounds bounds = sObjectMgr.GetExclusiveQuestGroupsMapBounds(qPrevInfo->GetExclusiveGroup()); ExclusiveQuestGroupsMapBounds bounds = sObjectMgr.GetExclusiveQuestGroupsMapBounds(qPrevInfo->GetExclusiveGroup());
@ -15494,7 +15536,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
m_bgData.bgTypeID = currentBg->GetTypeID(); // bg data not marked as modified m_bgData.bgTypeID = currentBg->GetTypeID(); // bg data not marked as modified
// join player to battleground group // join player to battleground group
currentBg->EventPlayerLoggedIn(this, GetObjectGuid()); currentBg->EventPlayerLoggedIn(this);
currentBg->AddOrSetPlayerToCorrectBgGroup(this, GetObjectGuid(), m_bgData.bgTeam); currentBg->AddOrSetPlayerToCorrectBgGroup(this, GetObjectGuid(), m_bgData.bgTeam);
SetInviteForBattleGroundQueueType(bgQueueTypeId, currentBg->GetInstanceID()); SetInviteForBattleGroundQueueType(bgQueueTypeId, currentBg->GetInstanceID());
@ -15722,17 +15764,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
m_rest_bonus = fields[21].GetFloat(); m_rest_bonus = fields[21].GetFloat();
if (time_diff > 0) if (time_diff > 0)
{ SetRestBonus(GetRestBonus() + ComputeRest(time_diff, true, (fields[23].GetInt32() > 0)));
// speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour)
float bubble0 = 0.031f;
// speed collect rest bonus in offline, in logout, in tavern, city (section/in hour)
float bubble1 = 0.125f;
float bubble = fields[23].GetUInt32() > 0
? bubble1 * sWorld.getConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_TAVERN_OR_CITY)
: bubble0 * sWorld.getConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_WILDERNESS);
SetRestBonus(GetRestBonus() + time_diff * ((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 72000)*bubble);
}
// load skills after InitStatsForLevel because it triggering aura apply also // load skills after InitStatsForLevel because it triggering aura apply also
_LoadSkills(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSKILLS)); _LoadSkills(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSKILLS));
@ -15933,6 +15965,43 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
return true; return true;
} }
bool Player::IsTappedByMeOrMyGroup(Creature* creature)
{
/* Nobody tapped the monster (solo kill by another NPC) */
if (!creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED))
{ return false; }
/* If there is a loot recipient, assign it to recipient */
if (Player* recipient = creature->GetLootRecipient())
{
/* See if we're in a group */
if (Group* plr_group = recipient->GetGroup())
{
/* Recipient is in a group... but is it ours? */
if (Group* my_group = GetGroup())
{
/* Check groups are the same */
if (plr_group != my_group)
{ return false; } // Cheater, deny loot
}
else
{ return false; } // We're not in a group, probably cheater
/* We're in the looters group, so mob is tapped by us */
return true;
}
/* We're not in a group, check to make sure we're the recipient (prevent cheaters) */
else if (recipient == this)
{ return true; }
}
else
/* Don't know what happened to the recipient, probably disconnected
* Either way, it isn't us, so mark as tapped */
{ return false; }
return false;
}
bool Player::isAllowedToLoot(Creature* creature) bool Player::isAllowedToLoot(Creature* creature)
{ {
// never tapped by any (mob solo kill) // never tapped by any (mob solo kill)
@ -21716,6 +21785,123 @@ void Player::SetTitle(CharTitlesEntry const* title, bool lost)
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
} }
void Player::UpdateRuneRegen(RuneType rune)
{
if (rune >= RUNE_DEATH)
return;
RuneType actualRune = rune;
float cooldown = RUNE_BASE_COOLDOWN;
for (uint8 i = 0; i < MAX_RUNES; i += 2)
{
if (GetBaseRune(i) != rune)
continue;
uint32 cd = GetRuneCooldown(i);
uint32 secondRuneCd = GetRuneCooldown(i + 1);
if (!cd && !secondRuneCd)
actualRune = GetCurrentRune(i);
else if (secondRuneCd && (cd > secondRuneCd || !cd))
{
cooldown = GetBaseRuneCooldown(i + 1);
actualRune = GetCurrentRune(i + 1);
}
else
{
cooldown = GetBaseRuneCooldown(i);
actualRune = GetCurrentRune(i);
}
break;
}
float auraMod = 1.0f;
Unit::AuraList const& regenAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for (Unit::AuraList::const_iterator i = regenAuras.begin(); i != regenAuras.end(); ++i)
if ((*i)->GetMiscValue() == POWER_RUNE && (*i)->GetSpellEffect()->EffectMiscValueB == rune)
auraMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
// Unholy Presence
if (Aura* aura = GetAura(48265, EFFECT_INDEX_0))
auraMod *= (100.0f + aura->GetModifier()->m_amount) / 100.0f;
// Runic Corruption
if (Aura* aura = GetAura(51460, EFFECT_INDEX_0))
auraMod *= (100.0f + aura->GetModifier()->m_amount) / 100.0f;
float hastePct = (100.0f - GetRatingBonusValue(CR_HASTE_MELEE)) / 100.0f;
if (hastePct < 0)
hastePct = 1.0f;
cooldown *= hastePct / auraMod;
float value = float(1 * IN_MILLISECONDS) / cooldown;
SetFloatValue(PLAYER_RUNE_REGEN_1 + uint8(actualRune), value);
}
void Player::UpdateRuneRegen()
{
for (uint8 i = 0; i < NUM_RUNE_TYPES; ++i)
UpdateRuneRegen(RuneType(i));
}
uint8 Player::GetRuneCooldownFraction(uint8 index) const
{
uint16 baseCd = GetBaseRuneCooldown(index);
if (!baseCd || !GetRuneCooldown(index))
return 255;
else if (baseCd == GetRuneCooldown(index))
return 0;
return uint8(float(baseCd - GetRuneCooldown(index)) / baseCd * 255);
}
void Player::AddRuneByAuraEffect(uint8 index, RuneType newType, Aura const* aura)
{
// Item - Death Knight T11 DPS 4P Bonus
if (newType == RUNE_DEATH && HasAura(90459))
CastSpell(this, 90507, true); // Death Eater
SetRuneConvertAura(index, aura); ConvertRune(index, newType);
}
void Player::RemoveRunesByAuraEffect(Aura const* aura)
{
for (uint8 i = 0; i < MAX_RUNES; ++i)
{
if (m_runes->runes[i].ConvertAura == aura)
{
ConvertRune(i, GetBaseRune(i));
SetRuneConvertAura(i, NULL);
}
}
}
void Player::RestoreBaseRune(uint8 index)
{
Aura const* aura = m_runes->runes[index].ConvertAura;
// If rune was converted by a non-pasive aura that still active we should keep it converted
if (aura && !IsPassiveSpell(aura->GetSpellProto()))
return;
// Blood of the North
if (aura->GetId() == 54637 && HasAura(54637))
return;
ConvertRune(index, GetBaseRune(index));
SetRuneConvertAura(index, NULL);
// Don't drop passive talents providing rune convertion
if (!aura || aura->GetModifier()->m_auraname != SPELL_AURA_CONVERT_RUNE)
return;
for (uint8 i = 0; i < MAX_RUNES; ++i)
if (aura == m_runes->runes[i].ConvertAura)
return;
if (Unit* target = aura->GetTarget())
target->RemoveSpellAuraHolder(const_cast<Aura*>(aura)->GetHolder());
}
void Player::ConvertRune(uint8 index, RuneType newType) void Player::ConvertRune(uint8 index, RuneType newType)
{ {
SetCurrentRune(index, newType); SetCurrentRune(index, newType);
@ -21749,7 +21935,7 @@ void Player::ResyncRunes()
for (uint32 i = 0; i < MAX_RUNES; ++i) for (uint32 i = 0; i < MAX_RUNES; ++i)
{ {
data << uint8(GetCurrentRune(i)); // rune type data << uint8(GetCurrentRune(i)); // rune type
data << uint8(255 - (GetRuneCooldown(i) * 51)); // passed cooldown time (0-255) data << uint8(GetRuneCooldownFraction(i));
} }
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
} }
@ -21761,16 +21947,6 @@ void Player::AddRunePower(uint8 index)
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
} }
static RuneType runeSlotTypes[MAX_RUNES] =
{
/*0*/ RUNE_BLOOD,
/*1*/ RUNE_BLOOD,
/*2*/ RUNE_UNHOLY,
/*3*/ RUNE_UNHOLY,
/*4*/ RUNE_FROST,
/*5*/ RUNE_FROST
};
void Player::InitRunes() void Player::InitRunes()
{ {
if (getClass() != CLASS_DEATH_KNIGHT) if (getClass() != CLASS_DEATH_KNIGHT)
@ -24066,6 +24242,77 @@ bool Player::FitArmorSpecializationRules(SpellEntry const * spellProto) const
return true; return true;
} }
float Player::ComputeRest(time_t timePassed, bool offline /*= false*/, bool inRestPlace /*= false*/)
{
// Every 8h in resting zone we gain a bubble
// A bubble is 5% of the total xp so there is 20 bubbles
// So we gain (total XP/20 every 8h) (8h = 288800 sec)
// (TotalXP/20)/28800; simplified to (TotalXP/576000) per second
// Client automatically double the value sent so we have to divide it by 2
// So final formula (TotalXP/1152000)
float bonus = timePassed * (GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 1152000.0f); // Get the gained rest xp for given second
if (!offline)
bonus *= sWorld.getConfig(CONFIG_FLOAT_RATE_REST_INGAME); // Apply the custom setting
else
{
if (inRestPlace)
bonus *= sWorld.getConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_TAVERN_OR_CITY);
else
bonus *= sWorld.getConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_WILDERNESS) / 4.0f; // bonus is reduced by 4 when not in rest place
}
return bonus;
}
float Player::GetCollisionHeight(bool mounted) const
{
if (mounted)
{
// mounted case
CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID));
if (!mountDisplayInfo)
return GetCollisionHeight(false);
CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelId);
if (!mountModelData)
return GetCollisionHeight(false);
CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId());
if (!displayInfo)
{
sLog.outError("GetCollisionHeight::Unable to find CreatureDisplayInfoEntry for %u", GetNativeDisplayId());
return 0;
}
CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelId);
if (!modelData)
{
sLog.outError("GetCollisionHeight::Unable to find CreatureModelDataEntry for %u", displayInfo->ModelId);
return 0;
}
float scaleMod = GetObjectScale(); // 99% sure about this
return scaleMod * mountModelData->MountHeight + modelData->CollisionHeight * 0.5f;
}
else
{
// use native model collision height in dismounted case
CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId());
if (!displayInfo)
{
sLog.outError("GetCollisionHeight::Unable to find CreatureDisplayInfoEntry for %u", GetNativeDisplayId());
return 0;
}
CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelId);
if (!modelData)
{
sLog.outError("GetCollisionHeight::Unable to find CreatureModelDataEntry for %u", displayInfo->ModelId);
return 0;
}
return modelData->CollisionHeight;
}
}
void Player::SendPetitionSignResult(ObjectGuid petitionGuid, Player* player, uint32 result) void Player::SendPetitionSignResult(ObjectGuid petitionGuid, Player* player, uint32 result)
{ {
WorldPacket data(SMSG_PETITION_SIGN_RESULTS, 8 + 8 + 4); WorldPacket data(SMSG_PETITION_SIGN_RESULTS, 8 + 8 + 4);

View file

@ -353,7 +353,12 @@ struct Areas
}; };
#define MAX_RUNES 6 #define MAX_RUNES 6
#define RUNE_COOLDOWN (2*5*IN_MILLISECONDS) // msec
enum RuneCooldowns
{
RUNE_BASE_COOLDOWN = 10000,
RUNE_MISS_COOLDOWN = 1500 // cooldown applied on runes when the spell misses
};
enum RuneType enum RuneType
{ {
@ -364,17 +369,30 @@ enum RuneType
NUM_RUNE_TYPES = 4 NUM_RUNE_TYPES = 4
}; };
static RuneType runeSlotTypes[MAX_RUNES] =
{
/*0*/ RUNE_BLOOD,
/*1*/ RUNE_BLOOD,
/*2*/ RUNE_UNHOLY,
/*3*/ RUNE_UNHOLY,
/*4*/ RUNE_FROST,
/*5*/ RUNE_FROST
};
struct RuneInfo struct RuneInfo
{ {
uint8 BaseRune; uint8 BaseRune;
uint8 CurrentRune; uint8 CurrentRune;
uint16 BaseCooldown;
uint16 Cooldown; // msec uint16 Cooldown; // msec
Aura const* ConvertAura;
}; };
struct Runes struct Runes
{ {
RuneInfo runes[MAX_RUNES]; RuneInfo runes[MAX_RUNES];
uint8 runeState; // mask of available runes uint8 runeState; // mask of available runes
uint32 lastUsedRuneMask;
void SetRuneState(uint8 index, bool set = true) void SetRuneState(uint8 index, bool set = true)
{ {
@ -1191,6 +1209,15 @@ class Player : public Unit
} }
void SetRestBonus(float rest_bonus_new); void SetRestBonus(float rest_bonus_new);
/**
* \brief: compute rest bonus
* \param: time_t timePassed > time from last check
* \param: bool offline > is the player was offline?
* \param: bool inRestPlace > if it was offline, is the player was in city/tavern/inn?
* \returns: float
**/
float ComputeRest(time_t timePassed, bool offline = false, bool inRestPlace = false);
RestType GetRestType() const RestType GetRestType() const
{ {
return rest_type; return rest_type;
@ -1539,6 +1566,9 @@ class Player : public Unit
void AddTimedQuest(uint32 quest_id) { m_timedquests.insert(quest_id); } void AddTimedQuest(uint32 quest_id) { m_timedquests.insert(quest_id); }
void RemoveTimedQuest(uint32 quest_id) { m_timedquests.erase(quest_id); } void RemoveTimedQuest(uint32 quest_id) { m_timedquests.erase(quest_id); }
//! Return collision height sent to client
float GetCollisionHeight(bool mounted) const;
/*********************************************************/ /*********************************************************/
/*** LOAD SYSTEM ***/ /*** LOAD SYSTEM ***/
/*********************************************************/ /*********************************************************/
@ -2058,6 +2088,10 @@ class Player : public Unit
StopMirrorTimer(FIRE_TIMER); StopMirrorTimer(FIRE_TIMER);
} }
void SetLevitate(bool enable) override;
void SetCanFly(bool enable) override;
void SetFeatherFall(bool enable) override;
void SetHover(bool enable) override;
void SetRoot(bool enable) override; void SetRoot(bool enable) override;
void SetWaterWalk(bool enable) override; void SetWaterWalk(bool enable) override;
@ -2371,6 +2405,7 @@ class Player : public Unit
bool isMoving() const { return m_movementInfo.HasMovementFlag(movementFlagsMask); } bool isMoving() const { return m_movementInfo.HasMovementFlag(movementFlagsMask); }
bool isMovingOrTurning() const { return m_movementInfo.HasMovementFlag(movementOrTurningFlagsMask); } bool isMovingOrTurning() const { return m_movementInfo.HasMovementFlag(movementOrTurningFlagsMask); }
bool CanSwim() const { return true; }
bool CanFly() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_CAN_FLY); } bool CanFly() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_CAN_FLY); }
bool IsFlying() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_FLYING); } bool IsFlying() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_FLYING); }
bool IsFreeFlying() const { return HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED) || HasAuraType(SPELL_AURA_FLY); } bool IsFreeFlying() const { return HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED) || HasAuraType(SPELL_AURA_FLY); }
@ -2498,7 +2533,8 @@ class Player : public Unit
GridReference<Player>& GetGridRef() { return m_gridRef; } GridReference<Player>& GetGridRef() { return m_gridRef; }
MapReference& GetMapRef() { return m_mapRef; } MapReference& GetMapRef() { return m_mapRef; }
bool IsTappedByMeOrMyGroup(Creature* creature);
bool isAllowedToLoot(Creature* creature); bool isAllowedToLoot(Creature* creature);
DeclinedName const* GetDeclinedNames() const { return m_declinedname; } DeclinedName const* GetDeclinedNames() const { return m_declinedname; }
@ -2508,10 +2544,22 @@ class Player : public Unit
RuneType GetBaseRune(uint8 index) const { return RuneType(m_runes->runes[index].BaseRune); } RuneType GetBaseRune(uint8 index) const { return RuneType(m_runes->runes[index].BaseRune); }
RuneType GetCurrentRune(uint8 index) const { return RuneType(m_runes->runes[index].CurrentRune); } RuneType GetCurrentRune(uint8 index) const { return RuneType(m_runes->runes[index].CurrentRune); }
uint16 GetRuneCooldown(uint8 index) const { return m_runes->runes[index].Cooldown; } uint16 GetRuneCooldown(uint8 index) const { return m_runes->runes[index].Cooldown; }
uint16 GetBaseRuneCooldown(uint8 index) const { return m_runes->runes[index].BaseCooldown; }
uint8 GetRuneCooldownFraction(uint8 index) const;
void UpdateRuneRegen(RuneType rune);
void UpdateRuneRegen();
bool IsBaseRuneSlotsOnCooldown(RuneType runeType) const; bool IsBaseRuneSlotsOnCooldown(RuneType runeType) const;
void ClearLastUsedRuneMask() { m_runes->lastUsedRuneMask = 0; }
bool IsLastUsedRune(uint8 index) const { return (m_runes->lastUsedRuneMask & (1 << index)) != 0; }
void SetLastUsedRune(RuneType type) { m_runes->lastUsedRuneMask |= 1 << uint32(type); }
void SetBaseRune(uint8 index, RuneType baseRune) { m_runes->runes[index].BaseRune = baseRune; } void SetBaseRune(uint8 index, RuneType baseRune) { m_runes->runes[index].BaseRune = baseRune; }
void SetCurrentRune(uint8 index, RuneType currentRune) { m_runes->runes[index].CurrentRune = currentRune; } void SetCurrentRune(uint8 index, RuneType currentRune) { m_runes->runes[index].CurrentRune = currentRune; }
void SetRuneCooldown(uint8 index, uint16 cooldown) { m_runes->runes[index].Cooldown = cooldown; m_runes->SetRuneState(index, (cooldown == 0) ? true : false); } void SetRuneCooldown(uint8 index, uint16 cooldown) { m_runes->runes[index].Cooldown = cooldown; m_runes->SetRuneState(index, (cooldown == 0) ? true : false); }
void SetBaseRuneCooldown(uint8 index, uint16 cooldown) { m_runes->runes[index].BaseCooldown = cooldown; }
void SetRuneConvertAura(uint8 index, Aura const* aura) { m_runes->runes[index].ConvertAura = aura; }
void AddRuneByAuraEffect(uint8 index, RuneType newType, Aura const* aura);
void RemoveRunesByAuraEffect(Aura const* aura);
void RestoreBaseRune(uint8 index);
void ConvertRune(uint8 index, RuneType newType); void ConvertRune(uint8 index, RuneType newType);
bool ActivateRunes(RuneType type, uint32 count); bool ActivateRunes(RuneType type, uint32 count);
void ResyncRunes(); void ResyncRunes();

View file

@ -811,6 +811,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
case 13139: // net-o-matic special effect case 13139: // net-o-matic special effect
case 23445: // evil twin case 23445: // evil twin
case 35679: // Protectorate Demolitionist case 35679: // Protectorate Demolitionist
case 37695: // Stanky
case 38637: // Nether Exhaustion (red) case 38637: // Nether Exhaustion (red)
case 38638: // Nether Exhaustion (green) case 38638: // Nether Exhaustion (green)
case 38639: // Nether Exhaustion (blue) case 38639: // Nether Exhaustion (blue)
@ -843,6 +844,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
return false; return false;
break; break;
case SPELL_AURA_MOD_DAMAGE_TAKEN: // dependent from bas point sign (positive -> negative) case SPELL_AURA_MOD_DAMAGE_TAKEN: // dependent from bas point sign (positive -> negative)
case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
if (spellEffect->CalculateSimpleValue() < 0) if (spellEffect->CalculateSimpleValue() < 0)
return true; return true;
// let check by target modes (for Amplify Magic cases/etc) // let check by target modes (for Amplify Magic cases/etc)
@ -1406,8 +1408,8 @@ struct DoSpellProcEvent
else else
++count; ++count;
} }
bool HasEntry(uint32 spellId) { return spe_map.count(spellId) > 0; } bool HasEntry(uint32 spellId) { return spe_map.find(spellId) != spe_map.end(); }
bool SetStateToEntry(uint32 spellId) { return (state = spe_map.find(spellId)) != spe_map.end(); } bool SetStateToEntry(uint32 spellId) { return (state = spe_map.find(spellId)) != spe_map.end(); }
SpellProcEventMap& spe_map; SpellProcEventMap& spe_map;
SpellProcEventMap::const_iterator state; SpellProcEventMap::const_iterator state;
@ -1694,7 +1696,7 @@ void SpellMgr::LoadSpellBonuses()
break; break;
} }
} }
direct_calc = CalculateDefaultCoefficient(spell, SPELL_DIRECT_DAMAGE) * (isHeal ? 1.88f : 1.0f); direct_calc = CalculateDefaultCoefficient(spell, SPELL_DIRECT_DAMAGE) * (isHeal ? SCALE_SPELLPOWER_HEALING : 1.0f);
direct_diff = std::abs(sbe.direct_damage - direct_calc); direct_diff = std::abs(sbe.direct_damage - direct_calc);
} }
@ -1716,7 +1718,7 @@ void SpellMgr::LoadSpellBonuses()
break; break;
} }
} }
dot_calc = CalculateDefaultCoefficient(spell, DOT) * (isHeal ? 1.88f : 1.0f); dot_calc = CalculateDefaultCoefficient(spell, DOT) * (isHeal ? SCALE_SPELLPOWER_HEALING : 1.0f);
dot_diff = std::abs(sbe.dot_damage - dot_calc); dot_diff = std::abs(sbe.dot_damage - dot_calc);
} }
@ -2874,7 +2876,7 @@ SpellEntry const* SpellMgr::SelectAuraRankForLevel(SpellEntry const* spellInfo,
break; break;
// if found appropriate level // if found appropriate level
if (level + 10 >= spellInfo->GetSpellLevel()) if (level + 10 >= nextSpellInfo->GetSpellLevel())
return nextSpellInfo; return nextSpellInfo;
// one rank less then // one rank less then
@ -3562,7 +3564,7 @@ void SpellMgr::LoadSpellScriptTarget()
{ {
if (itr->spellId == 30427 && !cInfo->SkinningLootId) if (itr->spellId == 30427 && !cInfo->SkinningLootId)
{ {
sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no skinLootid. Gas extraction will not work!", cInfo->Entry); sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no SkinningLootId. Gas extraction will not work!", cInfo->Entry);
sSpellScriptTargetStorage.EraseEntry(itr->spellId); sSpellScriptTargetStorage.EraseEntry(itr->spellId);
continue; continue;
} }

View file

@ -976,8 +976,8 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
{ {
SpellEntry const* shareSpell = (*itr)->GetSpellProto(); SpellEntry const* shareSpell = (*itr)->GetSpellProto();
uint32 shareDamage = uint32(damage*(*itr)->GetModifier()->m_amount / 100.0f); uint32 shareDamage = uint32(damage*(*itr)->GetModifier()->m_amount / 100.0f);
DealDamageMods(shareTarget, shareDamage, NULL); DealDamageMods(shareTarget, shareDamage, nullptr);
DealDamage(shareTarget, shareDamage, 0, damagetype, GetSpellSchoolMask(shareSpell), shareSpell, false); DealDamage(shareTarget, shareDamage, nullptr, damagetype, GetSpellSchoolMask(shareSpell), shareSpell, false);
} }
} }
} }
@ -1681,9 +1681,11 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage* damageInfo, int32 damage, S
{ return; } { return; }
if (!this || !pVictim) if (!this || !pVictim)
{ return; } return;
if (!this->IsAlive() || !pVictim->IsAlive())
{ return; } // units which are not alive cannot deal damage except for dying creatures
if ((!this->IsAlive() || !pVictim->IsAlive()) && (this->GetTypeId() != TYPEID_UNIT || this->getDeathState() != DEAD))
return;
// Check spell crit chance // Check spell crit chance
bool crit = IsSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType); bool crit = IsSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType);
@ -3521,7 +3523,7 @@ SpellMissInfo Unit::SpellHitResult(Unit* pVictim, SpellEntry const* spell, bool
return SPELL_MISS_EVADE; return SPELL_MISS_EVADE;
// Check for immune // Check for immune
if (pVictim->IsImmuneToSpell(spell, this == pVictim)) if (pVictim->IsImmuneToSpell(spell, this == pVictim) && !spell->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY))
return SPELL_MISS_IMMUNE; return SPELL_MISS_IMMUNE;
// All positive spells can`t miss // All positive spells can`t miss
@ -3530,7 +3532,7 @@ SpellMissInfo Unit::SpellHitResult(Unit* pVictim, SpellEntry const* spell, bool
return SPELL_MISS_NONE; return SPELL_MISS_NONE;
// Check for immune // Check for immune
if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell))) if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell)) && !spell->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY))
return SPELL_MISS_IMMUNE; return SPELL_MISS_IMMUNE;
// Try victim reflect spell // Try victim reflect spell
@ -4027,7 +4029,7 @@ void Unit::SetFacingToObject(WorldObject* pObject)
SetFacingTo(GetAngle(pObject)); SetFacingTo(GetAngle(pObject));
} }
bool Unit::isInAccessablePlaceFor(Creature const* c) const bool Unit::IsInAccessablePlaceFor(Creature const* c) const
{ {
if (IsInWater()) if (IsInWater())
return c->CanSwim(); return c->CanSwim();
@ -5875,7 +5877,7 @@ bool Unit::IsHostileTo(Unit const* unit) const
return false; return false;
// Sanctuary // Sanctuary
if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE))
return false; return false;
// PvP FFA state // PvP FFA state
@ -5987,7 +5989,7 @@ bool Unit::IsFriendlyTo(Unit const* unit) const
return true; return true;
// Sanctuary // Sanctuary
if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE))
return true; return true;
// PvP FFA state // PvP FFA state
@ -6661,6 +6663,17 @@ void Unit::EnergizeBySpell(Unit* pVictim, uint32 SpellID, uint32 Damage, Powers
pVictim->ModifyPower(powertype, Damage); pVictim->ModifyPower(powertype, Damage);
} }
/** Calculate spell coefficents and level penalties for spell/melee damage or heal
*
* this is the caster of the spell/ melee attacker
* @param spellProto SpellEntry of the used spell
* @param total current value onto which the Bonus and level penalty will be calculated
* @param benefit additional benefit from ie spellpower-auras
* @param ap_benefit additional melee attackpower benefit from auras
* @param damagetype what kind of damage
* @param donePart calculate for done or taken
* @param defCoeffMod default coefficient for additional scaling (i.e. normal player healing SCALE_SPELLPOWER_HEALING)
*/
int32 Unit::SpellBonusWithCoeffs(SpellEntry const* spellProto, int32 total, int32 benefit, int32 ap_benefit, DamageEffectType damagetype, bool donePart, float defCoeffMod) int32 Unit::SpellBonusWithCoeffs(SpellEntry const* spellProto, int32 total, int32 benefit, int32 ap_benefit, DamageEffectType damagetype, bool donePart, float defCoeffMod)
{ {
// Distribute Damage over multiple effects, reduce by AoE // Distribute Damage over multiple effects, reduce by AoE
@ -7119,7 +7132,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* pCaster, SpellEntry const* spellProto,
int32 TakenAdvertisedBenefit = SpellBaseDamageBonusTaken(GetSpellSchoolMask(spellProto)); int32 TakenAdvertisedBenefit = SpellBaseDamageBonusTaken(GetSpellSchoolMask(spellProto));
// apply benefit affected by spell power implicit coeffs and spell level penalties // apply benefit affected by spell power implicit coeffs and spell level penalties
TakenTotal = SpellBonusWithCoeffs(spellProto, TakenTotal, TakenAdvertisedBenefit, 0, damagetype, false); TakenTotal = pCaster->SpellBonusWithCoeffs(spellProto, TakenTotal, TakenAdvertisedBenefit, 0, damagetype, false);
float tmpDamage = (int32(pdamage) + TakenTotal * int32(stack)) * TakenTotalMod; float tmpDamage = (int32(pdamage) + TakenTotal * int32(stack)) * TakenTotalMod;
@ -7568,7 +7581,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* pVictim, SpellEntry const* spellProto,
int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(GetSpellSchoolMask(spellProto)); int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(GetSpellSchoolMask(spellProto));
// apply ap bonus and benefit affected by spell power implicit coeffs and spell level penalties // apply ap bonus and benefit affected by spell power implicit coeffs and spell level penalties
DoneTotal = SpellBonusWithCoeffs(spellProto, DoneTotal, DoneAdvertisedBenefit, 0, damagetype, true, 1.88f); DoneTotal = SpellBonusWithCoeffs(spellProto, DoneTotal, DoneAdvertisedBenefit, 0, damagetype, true, SCALE_SPELLPOWER_HEALING);
// use float as more appropriate for negative values and percent applying // use float as more appropriate for negative values and percent applying
float heal = (healamount + DoneTotal * int32(stack)) * DoneTotalMod; float heal = (healamount + DoneTotal * int32(stack)) * DoneTotalMod;
@ -7612,7 +7625,7 @@ uint32 Unit::SpellHealingBonusTaken(Unit* pCaster, SpellEntry const* spellProto,
int32 TakenAdvertisedBenefit = SpellBaseHealingBonusTaken(GetSpellSchoolMask(spellProto)); int32 TakenAdvertisedBenefit = SpellBaseHealingBonusTaken(GetSpellSchoolMask(spellProto));
// apply benefit affected by spell power implicit coeffs and spell level penalties // apply benefit affected by spell power implicit coeffs and spell level penalties
TakenTotal = SpellBonusWithCoeffs(spellProto, TakenTotal, TakenAdvertisedBenefit, 0, damagetype, false, 1.88f); TakenTotal = pCaster->SpellBonusWithCoeffs(spellProto, TakenTotal, TakenAdvertisedBenefit, 0, damagetype, false, SCALE_SPELLPOWER_HEALING);
AuraList const& mHealingGet = GetAurasByType(SPELL_AURA_MOD_HEALING_RECEIVED); AuraList const& mHealingGet = GetAurasByType(SPELL_AURA_MOD_HEALING_RECEIVED);
for (AuraList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i) for (AuraList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i)
@ -8155,7 +8168,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* pCaster, uint32 pdamage, WeaponAttackTy
if (!isWeaponDamageBasedSpell) if (!isWeaponDamageBasedSpell)
{ {
// apply benefit affected by spell power implicit coeffs and spell level penalties // apply benefit affected by spell power implicit coeffs and spell level penalties
TakenFlat = SpellBonusWithCoeffs(spellProto, 0, TakenFlat, 0, damagetype, false); TakenFlat = pCaster->SpellBonusWithCoeffs(spellProto, 0, TakenFlat, 0, damagetype, false);
} }
float tmpDamage = float(int32(pdamage) + TakenFlat * int32(stack)) * TakenPercent; float tmpDamage = float(int32(pdamage) + TakenFlat * int32(stack)) * TakenPercent;
@ -8257,6 +8270,10 @@ void Unit::Mount(uint32 mount, uint32 spellId)
pet->ApplyModeFlags(PET_MODE_DISABLE_ACTIONS, true); pet->ApplyModeFlags(PET_MODE_DISABLE_ACTIONS, true);
} }
} }
float height = ((Player*)this)->GetCollisionHeight(true);
if (height)
SendCollisionHeightUpdate(height);
} }
} }
@ -8284,9 +8301,17 @@ void Unit::Unmount(bool from_aura)
if (GetTypeId() == TYPEID_PLAYER) if (GetTypeId() == TYPEID_PLAYER)
{ {
if (Pet* pet = GetPet()) if (Pet* pet = GetPet())
pet->ApplyModeFlags(PET_MODE_DISABLE_ACTIONS, false); {
// Get reaction state and display appropriately
if (CharmInfo* charmInfo = pet->GetCharmInfo())
pet->SetModeFlags(PetModeFlags(charmInfo->GetReactState() | charmInfo->GetCommandState() * 0x100));
}
else else
{ ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny(); } ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny();
float height = ((Player*)this)->GetCollisionHeight(false);
if (height)
SendCollisionHeightUpdate(height);
} }
} }
@ -8687,8 +8712,23 @@ bool Unit::IsVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo
if (m_Visibility == VISIBILITY_OFF) if (m_Visibility == VISIBILITY_OFF)
return false; return false;
// grouped players should always see stealthed party members
if (GetTypeId() == TYPEID_PLAYER && u->GetTypeId() == TYPEID_PLAYER)
if (((Player*)this)->IsGroupVisibleFor(((Player*)u)) && u->IsFriendlyTo(this))
return true;
// raw invisibility // raw invisibility
bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask != 0); bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask != 0);
if (u->GetTypeId() == TYPEID_PLAYER) // if object is player with mover, use its visibility masks, so that an invisible player MCing a creature can see stuff
{
if (Player* player = (Player*)u)
{
if (Unit* mover=player->GetMover())
{
invisible= (m_invisibilityMask != 0 || mover->m_invisibilityMask != 0);
}
}
}
// detectable invisibility case // detectable invisibility case
if (invisible && ( if (invisible && (
@ -8705,35 +8745,18 @@ bool Unit::IsVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo
// special cases for always overwrite invisibility/stealth // special cases for always overwrite invisibility/stealth
if (invisible || m_Visibility == VISIBILITY_GROUP_STEALTH) if (invisible || m_Visibility == VISIBILITY_GROUP_STEALTH)
{ {
// non-hostile case if (u->IsHostileTo(this))
if (!u->IsHostileTo(this))
{
// player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting)
if (GetTypeId() == TYPEID_PLAYER && u->GetTypeId() == TYPEID_PLAYER)
{
if (((Player*)this)->IsGroupVisibleFor(((Player*)u)))
return true;
// else apply same rules as for hostile case (detecting check for stealth)
}
}
// hostile case
else
{ {
// Hunter mark functionality // Hunter mark functionality
AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED);
for (AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) for (AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
if ((*iter)->GetCasterGuid() == u->GetObjectGuid()) if ((*iter)->GetCasterGuid() == u->GetObjectGuid())
return true; return true;
// else apply detecting check for stealth
} }
// none other cases for detect invisibility, so invisible // none other cases for detect invisibility, so invisible
if (invisible) if (invisible)
return false; return false;
// else apply stealth detecting check
} }
// unit got in stealth in this moment and must ignore old detected state // unit got in stealth in this moment and must ignore old detected state
@ -9518,7 +9541,7 @@ bool Unit::SelectHostileTarget()
for (AuraList::const_reverse_iterator aura = tauntAuras.rbegin(); aura != tauntAuras.rend(); ++aura) for (AuraList::const_reverse_iterator aura = tauntAuras.rbegin(); aura != tauntAuras.rend(); ++aura)
{ {
if ((caster = (*aura)->GetCaster()) && caster->IsInMap(this) && if ((caster = (*aura)->GetCaster()) && caster->IsInMap(this) &&
caster->IsTargetableForAttack() && caster->isInAccessablePlaceFor((Creature*)this) && caster->IsTargetableForAttack() && caster->IsInAccessablePlaceFor((Creature*)this) &&
!IsSecondChoiceTarget(caster, true)) !IsSecondChoiceTarget(caster, true))
{ {
target = caster; target = caster;
@ -9581,7 +9604,7 @@ bool Unit::SelectHostileTarget()
{ {
for (AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr) for (AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr)
{ {
if ((*itr)->IsInMap(this) && (*itr)->IsTargetableForAttack() && (*itr)->isInAccessablePlaceFor((Creature*)this)) if ((*itr)->IsInMap(this) && (*itr)->IsTargetableForAttack() && (*itr)->IsInAccessablePlaceFor((Creature*)this))
return false; return false;
} }
} }
@ -12156,3 +12179,59 @@ void Unit::BuildMoveFeatherFallPacket(WorldPacket* data, bool apply, uint32 valu
} }
} }
void Unit::BuildMoveHoverPacket(WorldPacket* data, bool apply, uint32 value)
{
ObjectGuid guid = GetObjectGuid();
if (apply)
{
data->Initialize(SMSG_MOVE_SET_HOVER, 8 + 4 + 1);
data->WriteGuidMask<1, 4, 2, 3, 0, 5, 6, 7>(guid);
data->WriteGuidBytes<5, 4, 1, 2, 3, 6, 0, 7>(guid);
*data << uint32(0);
}
else
{
data->Initialize(SMSG_MOVE_UNSET_HOVER, 8 + 4 + 1);
data->WriteGuidMask<4, 6, 3, 1, 2, 7, 5, 0>(guid);
data->WriteGuidBytes<4, 5, 3, 6, 7, 1, 2, 0>(guid);
*data << uint32(0);
}
}
void Unit::BuildMoveLevitatePacket(WorldPacket* data, bool apply, uint32 value)
{
ObjectGuid guid = GetObjectGuid();
if (apply)
{
data->Initialize(SMSG_MOVE_GRAVITY_ENABLE);
data->WriteGuidMask<1, 4, 7, 5, 2, 0, 3, 6>(GetObjectGuid());
data->WriteGuidBytes<3>(GetObjectGuid());
*data << uint32(value);
data->WriteGuidBytes<7, 6, 4, 0, 1, 5, 2>(GetObjectGuid());
}
else
{
data->Initialize(SMSG_MOVE_GRAVITY_DISABLE);
data->WriteGuidMask<0, 1, 5, 7, 6, 4, 3, 2>(GetObjectGuid());
data->WriteGuidBytes<7, 2, 0>(GetObjectGuid());
*data << uint32(value);
data->WriteGuidBytes<5, 1, 3, 4, 6>(GetObjectGuid());
}
}
void Unit::SendCollisionHeightUpdate(float height)
{
if (GetTypeId() == TYPEID_PLAYER)
{
WorldPacket data(SMSG_MOVE_SET_COLLISION_HGT, GetPackGUID().size() + 4 + 4);
data.WriteGuidMask<6, 1, 4, 7, 5, 2, 0, 3>(GetObjectGuid());
data.WriteGuidBytes<6, 0, 4, 3, 5>(GetObjectGuid());
data << uint32(sWorld.GetGameTime()); // Packet counter
data.WriteGuidBytes<1, 2, 7>(GetObjectGuid());
data << ((Player*)this)->GetCollisionHeight(true);
((Player*)this)->GetSession()->SendPacket(&data);
}
}

View file

@ -150,6 +150,8 @@ enum SpellFacingFlags
#define BASE_ATTACK_TIME 2000 #define BASE_ATTACK_TIME 2000
#define BASE_BLOCK_DAMAGE_PERCENT 30 #define BASE_BLOCK_DAMAGE_PERCENT 30
#define SCALE_SPELLPOWER_HEALING 1.88f
/** /**
* byte value (UNIT_FIELD_BYTES_1,0). * byte value (UNIT_FIELD_BYTES_1,0).
* *
@ -225,9 +227,9 @@ enum UnitPVPStateFlags
UNIT_BYTE2_FLAG_PVP = 0x01, UNIT_BYTE2_FLAG_PVP = 0x01,
UNIT_BYTE2_FLAG_UNK1 = 0x02, UNIT_BYTE2_FLAG_UNK1 = 0x02,
UNIT_BYTE2_FLAG_FFA_PVP = 0x04, UNIT_BYTE2_FLAG_FFA_PVP = 0x04,
UNIT_BYTE2_FLAG_SANCTUARY = 0x08, UNIT_BYTE2_FLAG_SUPPORTABLE = 0x08, // allows for being targeted for healing/bandaging by friendlies
UNIT_BYTE2_FLAG_UNK4 = 0x10, UNIT_BYTE2_FLAG_AURAS = 0x10, // show possitive auras as positive, and allow its dispel
UNIT_BYTE2_FLAG_UNK5 = 0x20, UNIT_BYTE2_FLAG_UNK5 = 0x20, // show negative auras as positive, *not* allowing dispel (at least for pets)
UNIT_BYTE2_FLAG_UNK6 = 0x40, UNIT_BYTE2_FLAG_UNK6 = 0x40,
UNIT_BYTE2_FLAG_UNK7 = 0x80 UNIT_BYTE2_FLAG_UNK7 = 0x80
}; };
@ -596,7 +598,7 @@ enum UnitFlags
UNIT_FLAG_PVP = 0x00001000, // changed in 3.0.3 UNIT_FLAG_PVP = 0x00001000, // changed in 3.0.3
UNIT_FLAG_SILENCED = 0x00002000, // silenced, 2.1.1 UNIT_FLAG_SILENCED = 0x00002000, // silenced, 2.1.1
UNIT_FLAG_UNK_14 = 0x00004000, // 2.0.8 UNIT_FLAG_UNK_14 = 0x00004000, // 2.0.8
UNIT_FLAG_UNK_15 = 0x00008000, UNIT_FLAG_UNK_15 = 0x00008000, // related to jerky movement in water?
UNIT_FLAG_UNK_16 = 0x00010000, // removes attackable icon UNIT_FLAG_UNK_16 = 0x00010000, // removes attackable icon
UNIT_FLAG_PACIFIED = 0x00020000, // 3.0.3 ok UNIT_FLAG_PACIFIED = 0x00020000, // 3.0.3 ok
UNIT_FLAG_STUNNED = 0x00040000, // 3.0.3 ok UNIT_FLAG_STUNNED = 0x00040000, // 3.0.3 ok
@ -2399,7 +2401,7 @@ class Unit : public WorldObject
virtual bool IsInWater() const; virtual bool IsInWater() const;
virtual bool IsUnderWater() const; virtual bool IsUnderWater() const;
bool isInAccessablePlaceFor(Creature const* c) const; bool IsInAccessablePlaceFor(Creature const* c) const;
void SendHealSpellLog(Unit* pVictim, uint32 SpellID, uint32 Damage, uint32 OverHeal, bool critical = false, uint32 absorb = 0); void SendHealSpellLog(Unit* pVictim, uint32 SpellID, uint32 Damage, uint32 OverHeal, bool critical = false, uint32 absorb = 0);
void SendEnergizeSpellLog(Unit* pVictim, uint32 SpellID, uint32 Damage, Powers powertype); void SendEnergizeSpellLog(Unit* pVictim, uint32 SpellID, uint32 Damage, Powers powertype);
@ -2656,6 +2658,12 @@ class Unit : public WorldObject
bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_LEVITATING); } bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_LEVITATING); }
bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_WALK_MODE); } bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_WALK_MODE); }
bool IsRooted() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_ROOT); } bool IsRooted() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_ROOT); }
virtual void SetLevitate(bool /*enabled*/) {}
virtual void SetSwim(bool /*enabled*/) {}
virtual void SetCanFly(bool /*enabled*/) {}
virtual void SetFeatherFall(bool /*enabled*/) {}
virtual void SetHover(bool /*enabled*/) {}
virtual void SetRoot(bool /*enabled*/) {} virtual void SetRoot(bool /*enabled*/) {}
/** /**
* Changes this \ref Unit s ability to walk on water. * Changes this \ref Unit s ability to walk on water.
@ -3327,6 +3335,7 @@ class Unit : public WorldObject
// at any changes to Scale and/or displayId // at any changes to Scale and/or displayId
void UpdateModelData(); void UpdateModelData();
void SendCollisionHeightUpdate(float height);
DynamicObject* GetDynObject(uint32 spellId, SpellEffectIndex effIndex); DynamicObject* GetDynObject(uint32 spellId, SpellEffectIndex effIndex);
DynamicObject* GetDynObject(uint32 spellId); DynamicObject* GetDynObject(uint32 spellId);
@ -3485,6 +3494,9 @@ class Unit : public WorldObject
bool IsLinkingEventTrigger() const { return m_isCreatureLinkingTrigger; } bool IsLinkingEventTrigger() const { return m_isCreatureLinkingTrigger; }
virtual bool CanSwim() const = 0;
virtual bool CanFly() const = 0;
bool IsSplineEnabled() const; bool IsSplineEnabled() const;
bool IsInWorgenForm(bool inPermanent = false) const; bool IsInWorgenForm(bool inPermanent = false) const;
@ -3496,6 +3508,8 @@ class Unit : public WorldObject
void BuildSendPlayVisualPacket(WorldPacket* data, uint32 value, bool impact); void BuildSendPlayVisualPacket(WorldPacket* data, uint32 value, bool impact);
void BuildMoveSetCanFlyPacket(WorldPacket* data, bool apply, uint32 value); void BuildMoveSetCanFlyPacket(WorldPacket* data, bool apply, uint32 value);
void BuildMoveFeatherFallPacket(WorldPacket* data, bool apply, uint32 value); void BuildMoveFeatherFallPacket(WorldPacket* data, bool apply, uint32 value);
void BuildMoveHoverPacket(WorldPacket* data, bool apply, uint32 value);
void BuildMoveLevitatePacket(WorldPacket* data, bool apply, uint32 value);
protected: protected:
explicit Unit(); explicit Unit();

View file

@ -148,7 +148,7 @@ void HostileReference::updateOnlineStatus()
!getTarget()->IsTaxiFlying())) !getTarget()->IsTaxiFlying()))
{ {
Creature* creature = (Creature*) getSourceUnit(); Creature* creature = (Creature*) getSourceUnit();
online = getTarget()->isInAccessablePlaceFor(creature); online = getTarget()->IsInAccessablePlaceFor(creature);
if (!online) if (!online)
{ {
if (creature->AI()->canReachByRangeAttack(getTarget())) if (creature->AI()->canReachByRangeAttack(getTarget()))

View file

@ -86,7 +86,8 @@ DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequences
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt); DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt); DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt);
DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt); DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt); DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore(CreatureModelDatafmt);
DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt); // sCreatureModelDataStore
DBCStorage <CreatureTypeEntry> sCreatureTypeStore(CreatureTypefmt); DBCStorage <CreatureTypeEntry> sCreatureTypeStore(CreatureTypefmt);
DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore(CurrencyTypesfmt); DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore(CurrencyTypesfmt);
@ -511,21 +512,22 @@ void LoadDBCStores(const std::string& dataPath)
sChrClassXPowerTypesStore[entry->classId][entry->power] = index; sChrClassXPowerTypesStore[entry->classId][entry->power] = index;
sChrClassXPowerIndexStore[entry->classId][index] = entry->power; sChrClassXPowerIndexStore[entry->classId][index] = entry->power;
} }
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sChrRacesStore, dbcPath, "ChrRaces.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrRacesStore, dbcPath,"ChrRaces.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sCinematicSequencesStore, dbcPath, "CinematicSequences.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCinematicSequencesStore, dbcPath,"CinematicSequences.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sCreatureDisplayInfoStore, dbcPath, "CreatureDisplayInfo.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureDisplayInfoStore, dbcPath,"CreatureDisplayInfo.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sCreatureDisplayInfoExtraStore, dbcPath, "CreatureDisplayInfoExtra.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureDisplayInfoExtraStore,dbcPath,"CreatureDisplayInfoExtra.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sCreatureFamilyStore, dbcPath, "CreatureFamily.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureFamilyStore, dbcPath,"CreatureFamily.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sCreatureSpellDataStore, dbcPath, "CreatureSpellData.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureModelDataStore, dbcPath,"CreatureModelData.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sCreatureTypeStore, dbcPath, "CreatureType.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureSpellDataStore, dbcPath,"CreatureSpellData.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sCurrencyTypesStore, dbcPath, "CurrencyTypes.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureTypeStore, dbcPath,"CreatureType.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sDestructibleModelDataStore, dbcPath, "DestructibleModelData.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCurrencyTypesStore, dbcPath,"CurrencyTypes.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sDungeonEncounterStore, dbcPath, "DungeonEncounter.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDestructibleModelDataStore,dbcPath,"DestructibleModelData.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sDurabilityCostsStore, dbcPath, "DurabilityCosts.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDungeonEncounterStore, dbcPath,"DungeonEncounter.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sDurabilityQualityStore, dbcPath, "DurabilityQuality.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityCostsStore, dbcPath,"DurabilityCosts.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sEmotesStore, dbcPath, "Emotes.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityQualityStore, dbcPath,"DurabilityQuality.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sEmotesTextStore, dbcPath, "EmotesText.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sEmotesStore, dbcPath,"Emotes.dbc");
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sFactionStore, dbcPath, "Faction.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sEmotesTextStore, dbcPath,"EmotesText.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sFactionStore, dbcPath,"Faction.dbc");
for (uint32 i = 0; i < sFactionStore.GetNumRows(); ++i) for (uint32 i = 0; i < sFactionStore.GetNumRows(); ++i)
{ {
FactionEntry const* faction = sFactionStore.LookupEntry(i); FactionEntry const* faction = sFactionStore.LookupEntry(i);
@ -1004,6 +1006,87 @@ uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
return mapid; return mapid;
} }
ContentLevels GetContentLevelsForMap(uint32 mapid)
{
MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
if (!mapEntry)
return CONTENT_1_60;
// exceptions for 648 - Goblin Starter area and 654 - Worgen Starter area
if (mapid == 648 || mapid == 654)
return CONTENT_1_60;
switch (mapEntry->Expansion())
{
default: return CONTENT_1_60;
case 1: return CONTENT_61_70;
case 2: return CONTENT_71_80;
case 3: return CONTENT_81_85;
}
}
ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id)
{
// not sorted, numbering index from 0
for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
{
ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(i);
if (ch && ch->ChannelID == channel_id)
return ch;
}
return nullptr;
}
bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId)
{
if (requiredTotemCategoryId==0)
return true;
if (itemTotemCategoryId==0)
return false;
TotemCategoryEntry const* itemEntry = sTotemCategoryStore.LookupEntry(itemTotemCategoryId);
if (!itemEntry)
return false;
TotemCategoryEntry const* reqEntry = sTotemCategoryStore.LookupEntry(requiredTotemCategoryId);
if (!reqEntry)
return false;
if (itemEntry->categoryType!=reqEntry->categoryType)
return false;
return (itemEntry->categoryMask & reqEntry->categoryMask)==reqEntry->categoryMask;
}
bool Zone2MapCoordinates(float& x, float& y, uint32 zone)
{
WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
// if not listed then map coordinates (instance)
if (!maEntry || maEntry->x2 == maEntry->x1 || maEntry->y2 == maEntry->y1)
return false;
std::swap(x, y); // at client map coords swapped
x = x * ((maEntry->x2-maEntry->x1) / 100) + maEntry->x1;
y = y * ((maEntry->y2-maEntry->y1) / 100) + maEntry->y1; // client y coord from top to down
return true;
}
bool Map2ZoneCoordinates(float& x,float& y,uint32 zone)
{
WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
// if not listed then map coordinates (instance)
if (!maEntry || maEntry->x2 == maEntry->x1 || maEntry->y2 == maEntry->y1)
return false;
x = (x-maEntry->x1)/((maEntry->x2-maEntry->x1)/100);
y = (y-maEntry->y1)/((maEntry->y2-maEntry->y1)/100); // client y coord from top to down
std::swap(x,y); // client have map coords swapped
return true;
}
ContentLevels GetContentLevelsForMapAndZone(uint32 mapId, uint32 zoneId) ContentLevels GetContentLevelsForMapAndZone(uint32 mapId, uint32 zoneId)
{ {
MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
@ -1042,109 +1125,6 @@ ContentLevels GetContentLevelsForMapAndZone(uint32 mapId, uint32 zoneId)
} }
} }
ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id)
{
// not sorted, numbering index from 0
for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
{
ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(i);
if (ch && ch->ChannelID == channel_id)
return ch;
}
return NULL;
}
/*
static ChatChannelsEntry worldCh = { 26, 4, "world" };
ChatChannelsEntry const* GetChannelEntryFor(const std::string& name)
{
// not sorted, numbering index from 0
for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
{
ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(i);
if (ch)
{
// need to remove %s from entryName if it exists before we match
std::string entryName(ch->pattern[0]);
std::size_t removeString = entryName.find("%s");
if (removeString != std::string::npos)
entryName.replace(removeString, 2, "");
if (name.find(entryName) != std::string::npos)
return ch;
}
}
bool compare = true; // hack for world channel, TODO smth!
std::string world = "world";
for (uint8 i = 0; i < name.length(); ++i)
{
if (tolower(name[i]) != world[i])
{
compare = false;
break;
}
}
if (compare)
return &worldCh;
return NULL;
}
*/
bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId)
{
if (requiredTotemCategoryId == 0)
return true;
if (itemTotemCategoryId == 0)
return false;
TotemCategoryEntry const* itemEntry = sTotemCategoryStore.LookupEntry(itemTotemCategoryId);
if (!itemEntry)
return false;
TotemCategoryEntry const* reqEntry = sTotemCategoryStore.LookupEntry(requiredTotemCategoryId);
if (!reqEntry)
return false;
if (itemEntry->categoryType != reqEntry->categoryType)
return false;
return (itemEntry->categoryMask & reqEntry->categoryMask) == reqEntry->categoryMask;
}
bool Zone2MapCoordinates(float& x, float& y, uint32 zone)
{
WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
// if not listed then map coordinates (instance)
if (!maEntry || maEntry->x2 == maEntry->x1 || maEntry->y2 == maEntry->y1)
return false;
std::swap(x, y); // at client map coords swapped
x = x * ((maEntry->x2 - maEntry->x1) / 100) + maEntry->x1;
y = y * ((maEntry->y2 - maEntry->y1) / 100) + maEntry->y1; // client y coord from top to down
return true;
}
bool Map2ZoneCoordinates(float& x, float& y, uint32 zone)
{
WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
// if not listed then map coordinates (instance)
if (!maEntry || maEntry->x2 == maEntry->x1 || maEntry->y2 == maEntry->y1)
return false;
x = (x - maEntry->x1) / ((maEntry->x2 - maEntry->x1) / 100);
y = (y - maEntry->y1) / ((maEntry->y2 - maEntry->y1) / 100); // client y coord from top to down
std::swap(x, y); // client have map coords swapped
return true;
}
MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty) MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty)
{ {
MapDifficultyMap::const_iterator itr = sMapDifficultyMap.find(MAKE_PAIR32(mapId, difficulty)); MapDifficultyMap::const_iterator itr = sMapDifficultyMap.find(MAKE_PAIR32(mapId, difficulty));

View file

@ -141,6 +141,7 @@ extern DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore;
extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore; extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore;
extern DBCStorage <CreatureDisplayInfoExtraEntry>sCreatureDisplayInfoExtraStore; extern DBCStorage <CreatureDisplayInfoExtraEntry>sCreatureDisplayInfoExtraStore;
extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore; extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore;
extern DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore;
extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore; extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore;
extern DBCStorage <CreatureTypeEntry> sCreatureTypeStore; extern DBCStorage <CreatureTypeEntry> sCreatureTypeStore;
extern DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore; extern DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore;

View file

@ -751,19 +751,19 @@ struct CinematicSequencesEntry
struct CreatureDisplayInfoEntry struct CreatureDisplayInfoEntry
{ {
uint32 Displayid; // 0 m_ID uint32 Displayid; // 0 m_ID
// 1 m_modelID uint32 ModelId; // 1 m_modelID
// 2 m_soundID // 2 m_soundID
uint32 ExtendedDisplayInfoID; // 3 m_extendedDisplayInfoID -> CreatureDisplayInfoExtraEntry::DisplayExtraId uint32 ExtendedDisplayInfoID; // 3 m_extendedDisplayInfoID -> CreatureDisplayInfoExtraEntry::DisplayExtraId
float Scale; // 4 m_creatureModelScale float Scale; // 4 m_creatureModelScale
// 5 m_creatureModelAlpha // 5 m_creatureModelAlpha
// 6-8 m_textureVariation[3] // 6-8 m_textureVariation[3]
// 9 m_portraitTextureName // 9 m_portraitTextureName
// 10 m_sizeClass // 10 m_sizeClass
// 11 m_bloodID // 11 m_bloodID
// 12 m_NPCSoundID // 12 m_NPCSoundID
// 13 m_particleColorID // 13 m_particleColorID
// 14 m_creatureGeosetData // 14 m_creatureGeosetData
// 15 m_objectEffectPackageID // 15 m_objectEffectPackageID
// 16 all 0 // 16 all 0
}; };
@ -797,6 +797,28 @@ struct CreatureFamilyEntry
// 11 m_iconFile // 11 m_iconFile
}; };
struct CreatureModelDataEntry
{
uint32 Id; // 0
//uint32 Flags; // 1
//char* ModelPath // 2
//uint32 InhabitType; // 3 model inhabit type
//float Scale; // 4 Used in calculation of unit collision data
//int32 Unk2 // 5
//int32 Unk3 // 6
//uint32 Unk4 // 7
//uint32 Unk5 // 8
//float Unk6 // 9
//uint32 Unk7 // 10
//float Unk8 // 11
//uint32 Unk9 // 12
//uint32 Unk10 // 13
//float CollisionWidth; // 14
float CollisionHeight; // 15
float MountHeight; // 16 Used in calculation of unit collision data when mounted
//float Unks[14] // 17-30
};
#define MAX_CREATURE_SPELL_DATA_SLOT 4 #define MAX_CREATURE_SPELL_DATA_SLOT 4
struct CreatureSpellDataEntry struct CreatureSpellDataEntry
@ -861,7 +883,7 @@ struct DestructibleModelDataEntry
// uint32 unk17; // 17 // uint32 unk17; // 17
// uint32 unk18; // 18 // uint32 unk18; // 18
// uint32 unk19; // 19 // uint32 unk19; // 19
//uint32 smokeDisplayId; // 20 uint32 smokeDisplayId; // 20
// uint32 unk21; // 21 // uint32 unk21; // 21
// uint32 unk22; // 22 // uint32 unk22; // 22
// uint32 unk23; // 23 // uint32 unk23; // 23
@ -1380,7 +1402,6 @@ struct MapEntry
MapID == 509 || MapID == 534 || MapID == 560 || // AhnQiraj, HyjalPast, HillsbradPast MapID == 509 || MapID == 534 || MapID == 560 || // AhnQiraj, HyjalPast, HillsbradPast
MapID == 568 || MapID == 580 || MapID == 595 || // ZulAman, Sunwell Plateau, Culling of Stratholme MapID == 568 || MapID == 580 || MapID == 595 || // ZulAman, Sunwell Plateau, Culling of Stratholme
MapID == 603 || MapID == 615 || MapID == 616 || // Ulduar, The Obsidian Sanctum, The Eye Of Eternity MapID == 603 || MapID == 615 || MapID == 616 || // Ulduar, The Obsidian Sanctum, The Eye Of Eternity
MapID == 603 || MapID == 615 || MapID == 616 || // Ulduar, The Obsidian Sanctum, The Eye Of Eternity
MapID == 631 || MapID == 658 || MapID == 724 || // Icecrown Citadel, Pit of Saron, Ruby Sanctum MapID == 631 || MapID == 658 || MapID == 724 || // Icecrown Citadel, Pit of Saron, Ruby Sanctum
MapID == 644 || MapID == 720 || MapID == 721 || // Halls of Origination, Firelands MapID == 644 || MapID == 720 || MapID == 721 || // Halls of Origination, Firelands
MapID == 734 || MapID == 755 || MapID == 859 || // Ahn'Qiraj Terrace, Lost City of Tol'Vir, Zul'Gurub MapID == 734 || MapID == 755 || MapID == 859 || // Ahn'Qiraj Terrace, Lost City of Tol'Vir, Zul'Gurub
@ -1723,81 +1744,89 @@ struct ClassFamilyMask
// SpellAuraOptions.dbc // SpellAuraOptions.dbc
struct SpellAuraOptionsEntry struct SpellAuraOptionsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
uint32 StackAmount; // 51 m_cumulativeAura uint32 StackAmount; // 1 m_cumulativeAura
uint32 procChance; // 38 m_procChance uint32 procChance; // 2 m_procChance
uint32 procCharges; // 39 m_procCharges uint32 procCharges; // 3 m_procCharges
uint32 procFlags; // 37 m_procTypeMask uint32 procFlags; // 4 m_procTypeMask
}; };
// SpellAuraRestrictions.dbc // SpellAuraRestrictions.dbc
struct SpellAuraRestrictionsEntry struct SpellAuraRestrictionsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
uint32 CasterAuraState; // 21 m_casterAuraState uint32 CasterAuraState; // 1 m_casterAuraState
uint32 TargetAuraState; // 22 m_targetAuraState uint32 TargetAuraState; // 2 m_targetAuraState
uint32 CasterAuraStateNot; // 23 m_excludeCasterAuraState uint32 CasterAuraStateNot; // 3 m_excludeCasterAuraState
uint32 TargetAuraStateNot; // 24 m_excludeTargetAuraState uint32 TargetAuraStateNot; // 4 m_excludeTargetAuraState
uint32 casterAuraSpell; // 25 m_casterAuraSpell uint32 casterAuraSpell; // 5 m_casterAuraSpell
uint32 targetAuraSpell; // 26 m_targetAuraSpell uint32 targetAuraSpell; // 6 m_targetAuraSpell
uint32 excludeCasterAuraSpell; // 27 m_excludeCasterAuraSpell uint32 excludeCasterAuraSpell; // 7 m_excludeCasterAuraSpell
uint32 excludeTargetAuraSpell; // 28 m_excludeTargetAuraSpell uint32 excludeTargetAuraSpell; // 8 m_excludeTargetAuraSpell
}; };
// SpellCastingRequirements.dbc // SpellCastingRequirements.dbc
struct SpellCastingRequirementsEntry struct SpellCastingRequirementsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
uint32 FacingCasterFlags; // 20 m_facingCasterFlags uint32 FacingCasterFlags; // 1 m_facingCasterFlags
//uint32 MinFactionId; // 159 m_minFactionID not used //uint32 MinFactionId; // 2 m_minFactionID not used
//uint32 MinReputation; // 160 m_minReputation not used //uint32 MinReputation; // 3 m_minReputation not used
int32 AreaGroupId; // 164 m_requiredAreaGroupId int32 AreaGroupId; // 4 m_requiredAreaGroupId
//uint32 RequiredAuraVision; // 161 m_requiredAuraVision not used //uint32 RequiredAuraVision; // 5 m_requiredAuraVision not used
uint32 RequiresSpellFocus; // 19 m_requiresSpellFocus uint32 RequiresSpellFocus; // 6 m_requiresSpellFocus
};
// SpellCastTimes.dbc
struct SpellCastTimesEntry
{
uint32 ID; // 0 m_ID
int32 CastTime; // 1 m_base
float CastTimePerLevel; // 2 m_perLevel
int32 MinCastTime; // 3 m_minimum
}; };
// SpellCategories.dbc // SpellCategories.dbc
struct SpellCategoriesEntry struct SpellCategoriesEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
uint32 Category; // 1 m_category uint32 Category; // 1 m_category
uint32 DmgClass; // 153 m_defenseType uint32 DmgClass; // 2 m_defenseType
uint32 Dispel; // 2 m_dispelType uint32 Dispel; // 3 m_dispelType
uint32 Mechanic; // 3 m_mechanic uint32 Mechanic; // 4 m_mechanic
uint32 PreventionType; // 154 m_preventionType uint32 PreventionType; // 5 m_preventionType
uint32 StartRecoveryCategory; // 145 m_startRecoveryCategory uint32 StartRecoveryCategory; // 6 m_startRecoveryCategory
}; };
// SpellClassOptions.dbc // SpellClassOptions.dbc
struct SpellClassOptionsEntry struct SpellClassOptionsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
//uint32 modalNextSpell; // 50 m_modalNextSpell not used //uint32 modalNextSpell; // 1 m_modalNextSpell not used
ClassFamilyMask SpellFamilyFlags; // 149-151 m_spellClassMask NOTE: size is 12 bytes!!! ClassFamilyMask SpellFamilyFlags; // 2-4 m_spellClassMask NOTE: size is 12 bytes!!!
uint32 SpellFamilyName; // 148 m_spellClassSet uint32 SpellFamilyName; // 5 m_spellClassSet
//char* Description; // 6 4.0.0 //char* Description; // 6 4.0.0
// helpers // helpers
bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const
{ {
return SpellFamilyFlags.IsFitToFamilyMask(familyFlags, familyFlags2); return SpellFamilyFlags.IsFitToFamilyMask(familyFlags, familyFlags2);
} }
bool IsFitToFamily(SpellFamily family, uint64 familyFlags, uint32 familyFlags2 = 0) const bool IsFitToFamily(SpellFamily family, uint64 familyFlags, uint32 familyFlags2 = 0) const
{ {
return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(familyFlags, familyFlags2); return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(familyFlags, familyFlags2);
} }
bool IsFitToFamilyMask(ClassFamilyMask const& mask) const bool IsFitToFamilyMask(ClassFamilyMask const& mask) const
{ {
return SpellFamilyFlags.IsFitToFamilyMask(mask); return SpellFamilyFlags.IsFitToFamilyMask(mask);
} }
bool IsFitToFamily(SpellFamily family, ClassFamilyMask const& mask) const bool IsFitToFamily(SpellFamily family, ClassFamilyMask const& mask) const
{ {
return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(mask); return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(mask);
} }
private: private:
// catch wrong uses // catch wrong uses
@ -1808,10 +1837,10 @@ struct SpellClassOptionsEntry
// SpellCooldowns.dbc // SpellCooldowns.dbc
struct SpellCooldownsEntry struct SpellCooldownsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
uint32 CategoryRecoveryTime; // 31 m_categoryRecoveryTime uint32 CategoryRecoveryTime; // 1 m_categoryRecoveryTime
uint32 RecoveryTime; // 30 m_recoveryTime uint32 RecoveryTime; // 2 m_recoveryTime
uint32 StartRecoveryTime; // 146 m_startRecoveryTime uint32 StartRecoveryTime; // 3 m_startRecoveryTime
}; };
// SpellEffect.dbc // SpellEffect.dbc
@ -1841,7 +1870,8 @@ struct SpellEffectEntry
uint32 EffectImplicitTargetB; // 23 m_implicitTargetB uint32 EffectImplicitTargetB; // 23 m_implicitTargetB
uint32 EffectSpellId; // 24 m_spellId - spell.dbc uint32 EffectSpellId; // 24 m_spellId - spell.dbc
uint32 EffectIndex; // 25 m_spellEffectIdx uint32 EffectIndex; // 25 m_spellEffectIdx
// uint32 unk; // 26 4.2.0 only 0 or 1 //uint32 unk; // 26 4.2.0 only 0 or 1
// helpers // helpers
int32 CalculateSimpleValue() const { return EffectBasePoints; } int32 CalculateSimpleValue() const { return EffectBasePoints; }
@ -1858,66 +1888,138 @@ struct SpellEffectEntry
// SpellEquippedItems.dbc // SpellEquippedItems.dbc
struct SpellEquippedItemsEntry struct SpellEquippedItemsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
int32 EquippedItemClass; // 70 m_equippedItemClass (value) int32 EquippedItemClass; // 1 m_equippedItemClass (value)
int32 EquippedItemInventoryTypeMask; // 72 m_equippedItemInvTypes (mask) int32 EquippedItemInventoryTypeMask; // 2 m_equippedItemInvTypes (mask)
int32 EquippedItemSubClassMask; // 71 m_equippedItemSubclass (mask) int32 EquippedItemSubClassMask; // 3 m_equippedItemSubclass (mask)
};
// SpellFocusObject.dbc
struct SpellFocusObjectEntry
{
uint32 ID; // 0 m_ID
//char* Name; // 1 m_name_lang
}; };
// SpellInterrupts.dbc // SpellInterrupts.dbc
struct SpellInterruptsEntry struct SpellInterruptsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
uint32 AuraInterruptFlags; // 33 m_auraInterruptFlags uint32 AuraInterruptFlags; // 1 m_auraInterruptFlags
//uint32 // 34 4.0.0 //uint32 // 2 4.0.0
uint32 ChannelInterruptFlags; // 35 m_channelInterruptFlags uint32 ChannelInterruptFlags; // 3 m_channelInterruptFlags
//uint32 // 36 4.0.0 //uint32 // 4 4.0.0
uint32 InterruptFlags; // 32 m_interruptFlags uint32 InterruptFlags; // 5 m_interruptFlags
};
// SpellItemEnchantment.dbc
struct SpellItemEnchantmentEntry
{
uint32 ID; // 0 m_ID
//uint32 charges; // 1 m_charges
uint32 type[3]; // 2-4 m_effect[3]
uint32 amount[3]; // 5-7 m_effectPointsMin[3]
//uint32 amount2[3] // 8-10 m_effectPointsMax[3]
uint32 spellid[3]; // 11-13 m_effectArg[3]
DBCString description; // 14 m_name_lang
uint32 aura_id; // 15 m_itemVisual
uint32 slot; // 16 m_flags
uint32 GemID; // 17 m_src_itemID
uint32 EnchantmentCondition; // 18 m_condition_id
uint32 requiredSkill; // 19 m_requiredSkillID
uint32 requiredSkillValue; // 20 m_requiredSkillRank
uint32 requiredLevel; // 21 m_requiredLevel - 3.1
// 22 new in 3.1
};
// SpellItemEnchantmentCondition.dbc
struct SpellItemEnchantmentConditionEntry
{
uint32 ID; // 0 m_ID
uint8 Color[5]; // 1-5 m_lt_operandType[5]
//uint32 LT_Operand[5]; // 6-10 m_lt_operand[5]
uint8 Comparator[5]; // 11-15 m_operator[5]
uint8 CompareColor[5]; // 15-20 m_rt_operandType[5]
uint32 Value[5]; // 21-25 m_rt_operand[5]
//uint8 Logic[5] // 25-30 m_logic[5]
}; };
// SpellLevels.dbc // SpellLevels.dbc
struct SpellLevelsEntry struct SpellLevelsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
uint32 baseLevel; // 41 m_baseLevel uint32 baseLevel; // 1 m_baseLevel
uint32 maxLevel; // 40 m_maxLevel uint32 maxLevel; // 2 m_maxLevel
uint32 spellLevel; // 42 m_spellLevel uint32 spellLevel; // 3 m_spellLevel
}; };
// SpellPower.dbc // SpellPower.dbc
struct SpellPowerEntry struct SpellPowerEntry
{ {
//uint32 Id; // 0 - m_ID //uint32 Id; // 0 - m_ID
uint32 manaCost; // 1 - m_manaCost uint32 manaCost; // 1 - m_manaCost
uint32 manaCostPerlevel; // 2 - m_manaCostPerLevel uint32 manaCostPerlevel; // 2 - m_manaCostPerLevel
uint32 ManaCostPercentage; // 3 - m_manaCostPct uint32 ManaCostPercentage; // 3 - m_manaCostPct
uint32 manaPerSecond; // 4 - m_manaPerSecond uint32 manaPerSecond; // 4 - m_manaPerSecond
//uint32 PowerDisplayId; // 5 - m_powerDisplayID - id from PowerDisplay.dbc, new in 3.1 uint32 manaPerSecondPerLevel; // 5 m_manaPerSecondPerLevel
//uint32 unk1; // 6 - 4.0.0 //uint32 PowerDisplayId; // 6 - m_powerDisplayID - id from PowerDisplay.dbc, new in 3.1
//unk // 7 - 4.3.0 float ManaCostPercentageFloat; // 7 4.3.0
};
// SpellRadius.dbc
struct SpellRadiusEntry
{
uint32 ID; // 0 m_ID
float Radius; // 1 m_radius
float RadiusPerLevel; // 2 m_radiusPerLevel
float RadiusMax; // 3 m_radiusMax
};
// SpellRange.dbc
struct SpellRangeEntry
{
uint32 ID; // 0 m_ID
float minRange; // 1 m_rangeMin[2]
float minRangeFriendly; // 2
float maxRange; // 3 m_rangeMax[2]
float maxRangeFriendly; // 4
uint32 type; // 5 m_flags
//char* Name; // 6-21 m_displayName_lang
//char* ShortName; // 23-38 m_displayNameShort_lang
}; };
// SpellReagents.dbc // SpellReagents.dbc
struct SpellReagentsEntry struct SpellReagentsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
int32 Reagent[MAX_SPELL_REAGENTS]; // 54-61 m_reagent int32 Reagent[MAX_SPELL_REAGENTS]; // 54-61 m_reagent
uint32 ReagentCount[MAX_SPELL_REAGENTS]; // 62-69 m_reagentCount uint32 ReagentCount[MAX_SPELL_REAGENTS]; // 62-69 m_reagentCount
}; };
// SpellRuneCost.dbc
struct SpellRuneCostEntry
{
uint32 ID; // 0 m_ID
uint32 RuneCost[3]; // 1-3 m_blood m_unholy m_frost (0=blood, 1=frost, 2=unholy)
uint32 runePowerGain; // 4 m_runicPower
bool NoRuneCost() const { return RuneCost[0] == 0 && RuneCost[1] == 0 && RuneCost[2] == 0; }
bool NoRunicPowerGain() const { return runePowerGain == 0; }
};
// SpellScaling.dbc // SpellScaling.dbc
struct SpellScalingEntry struct SpellScalingEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
int32 castTimeMin; // 1 uint32 castTimeMin; // 1
int32 castTimeMax; // 2 uint32 castTimeMax; // 2
int32 castScalingMaxLevel; // 3 uint32 castScalingMaxLevel; // 3
int32 playerClass; // 4 (index * 100) + charLevel => gtSpellScaling.dbc uint32 playerClass; // 4 (index * 100) + charLevel => gtSpellScaling.dbc
float coeff1[3]; // 5-7 float coeff1[3]; // 5-7
float coeff2[3]; // 8-10 float coeff2[3]; // 8-10
float coeff3[3]; // 11-13 float coeff3[3]; // 11-13
float coefBase; // 14 some coefficient, mostly 1.0f float coefBase; // 14 some coefficient, mostly 1.0f
int32 coefLevelBase; // 15 some level uint32 coefLevelBase; // 15 some level
bool IsScalableEffect(SpellEffectIndex i) const { return coeff1[i] != 0.0f; }; bool IsScalableEffect(SpellEffectIndex i) const { return coeff1[i] != 0.0f; };
}; };
@ -1925,18 +2027,37 @@ struct SpellScalingEntry
// SpellShapeshift.dbc // SpellShapeshift.dbc
struct SpellShapeshiftEntry struct SpellShapeshiftEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
uint32 StancesNot; // 13 m_shapeshiftMask uint32 StancesNot; // 1 m_shapeshiftMask
// uint32 unk_320_2; // 14 3.2.0 // uint32 unk_320_2; // 2 3.2.0
uint32 Stances; // 15 m_shapeshiftExclude uint32 Stances; // 3 m_shapeshiftExclude
// uint32 unk_320_3; // 16 3.2.0 // uint32 unk_320_3; // 4 3.2.0
// uint32 StanceBarOrder; // 155 m_stanceBarOrder not used // uint32 StanceBarOrder; // 5 m_stanceBarOrder not used
};
// SpellShapeshiftForm.dbc
struct SpellShapeshiftFormEntry
{
uint32 ID; // 0 m_ID
//uint32 buttonPosition; // 1 m_bonusActionBar
//char* Name; // 2 m_name_lang
uint32 flags1; // 3 m_flags
int32 creatureType; // 4 m_creatureType <=0 humanoid, other normal creature types
//uint32 unk1; // 5 m_attackIconID
uint32 attackSpeed; // 6 m_combatRoundTime
uint32 modelID_A; // 7 m_creatureDisplayID[4]
uint32 modelID_H; // 8
//uint32 unk3; // 9 unused always 0
//uint32 unk4; // 10 unused always 0
uint32 spellId[8]; // 11-18 m_presetSpellID[8]
//uint32 unk5; // 19 unused, !=0 for flight forms
//uint32 unk6; // 20
}; };
// SpellTargetRestrictions.dbc // SpellTargetRestrictions.dbc
struct SpellTargetRestrictionsEntry struct SpellTargetRestrictionsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
float MaxTargetRadius; // 1 - m_maxTargetRadius float MaxTargetRadius; // 1 - m_maxTargetRadius
uint32 MaxAffectedTargets; // 1 - m_maxTargets uint32 MaxAffectedTargets; // 1 - m_maxTargets
uint32 MaxTargetLevel; // 2 - m_maxTargetLevel uint32 MaxTargetLevel; // 2 - m_maxTargetLevel
@ -1947,9 +2068,9 @@ struct SpellTargetRestrictionsEntry
// SpellTotems.dbc // SpellTotems.dbc
struct SpellTotemsEntry struct SpellTotemsEntry
{ {
//uint32 Id; // 0 m_ID //uint32 Id; // 0 m_ID
uint32 TotemCategory[MAX_SPELL_TOTEM_CATEGORIES]; // 162-163 m_requiredTotemCategoryID uint32 TotemCategory[MAX_SPELL_TOTEM_CATEGORIES]; // 1 2 m_requiredTotemCategoryID
uint32 Totem[MAX_SPELL_TOTEMS]; // 52-53 m_totem uint32 Totem[MAX_SPELL_TOTEMS]; // 3 4 m_totem
}; };
// Spell.dbc // Spell.dbc
@ -2116,68 +2237,6 @@ struct SpellEntry
#define LOADED_SPELLDBC_FIELD_POS_EQUIPPED_ITEM_CLASS 65 // Must be converted to -1 #define LOADED_SPELLDBC_FIELD_POS_EQUIPPED_ITEM_CLASS 65 // Must be converted to -1
#define LOADED_SPELLDBC_FIELD_POS_SPELLNAME_0 132 // Links to "MaNGOS server-side spell" #define LOADED_SPELLDBC_FIELD_POS_SPELLNAME_0 132 // Links to "MaNGOS server-side spell"
struct SpellCastTimesEntry
{
uint32 ID; // 0 m_ID
int32 CastTime; // 1 m_base
float CastTimePerLevel; // 2 m_perLevel
int32 MinCastTime; // 3 m_minimum
};
struct SpellFocusObjectEntry
{
uint32 ID; // 0 m_ID
//char* Name; // 1 m_name_lang
};
struct SpellRadiusEntry
{
uint32 ID; // 0 m_ID
float Radius; // 1 m_radius
// 2 m_radiusPerLevel
//float RadiusMax; // 3 m_radiusMax
};
struct SpellRangeEntry
{
uint32 ID; // 0 m_ID
float minRange; // 1 m_rangeMin[2]
float minRangeFriendly; // 2
float maxRange; // 3 m_rangeMax[2]
float maxRangeFriendly; // 4
//uint32 Flags; // 5 m_flags
//char* Name; // 6-21 m_displayName_lang
//char* ShortName; // 23-38 m_displayNameShort_lang
};
struct SpellRuneCostEntry
{
uint32 ID; // 0 m_ID
uint32 RuneCost[3]; // 1-3 m_blood m_unholy m_frost (0=blood, 1=frost, 2=unholy)
uint32 runePowerGain; // 4 m_runicPower
bool NoRuneCost() const { return RuneCost[0] == 0 && RuneCost[1] == 0 && RuneCost[2] == 0; }
bool NoRunicPowerGain() const { return runePowerGain == 0; }
};
struct SpellShapeshiftFormEntry
{
uint32 ID; // 0 m_ID
//uint32 buttonPosition; // 1 m_bonusActionBar
//char* Name; // 2 m_name_lang
uint32 flags1; // 3 m_flags
int32 creatureType; // 4 m_creatureType <=0 humanoid, other normal creature types
//uint32 unk1; // 5 m_attackIconID
uint32 attackSpeed; // 6 m_combatRoundTime
uint32 modelID_A; // 7 m_creatureDisplayID[4]
uint32 modelID_H; // 8
//uint32 unk3; // 9 unused always 0
//uint32 unk4; // 10 unused always 0
uint32 spellId[8]; // 11-18 m_presetSpellID[8]
//uint32 unk5; // 19 unused, !=0 for flight forms
//uint32 unk6; // 20
};
struct SpellDifficultyEntry struct SpellDifficultyEntry
{ {
uint32 ID; // 0 m_ID uint32 ID; // 0 m_ID
@ -2190,36 +2249,6 @@ struct SpellDurationEntry
int32 Duration[3]; // m_duration, m_durationPerLevel, m_maxDuration int32 Duration[3]; // m_duration, m_durationPerLevel, m_maxDuration
}; };
struct SpellItemEnchantmentEntry
{
uint32 ID; // 0 m_ID
//uint32 charges; // 1 m_charges
uint32 type[3]; // 2-4 m_effect[3]
uint32 amount[3]; // 5-7 m_effectPointsMin[3]
//uint32 amount2[3] // 8-10 m_effectPointsMax[3]
uint32 spellid[3]; // 11-13 m_effectArg[3]
DBCString description; // 14 m_name_lang
uint32 aura_id; // 15 m_itemVisual
uint32 slot; // 16 m_flags
uint32 GemID; // 17 m_src_itemID
uint32 EnchantmentCondition; // 18 m_condition_id
//uint32 requiredSkill; // 19 m_requiredSkillID
//uint32 requiredSkillValue; // 20 m_requiredSkillRank
// 21 new in 3.1
// 22 new in 3.1
};
struct SpellItemEnchantmentConditionEntry
{
uint32 ID; // 0 m_ID
uint8 Color[5]; // 1-5 m_lt_operandType[5]
//uint32 LT_Operand[5]; // 6-10 m_lt_operand[5]
uint8 Comparator[5]; // 11-15 m_operator[5]
uint8 CompareColor[5]; // 15-20 m_rt_operandType[5]
uint32 Value[5]; // 21-25 m_rt_operand[5]
//uint8 Logic[5] // 25-30 m_logic[5]
};
struct SummonPropertiesEntry struct SummonPropertiesEntry
{ {
uint32 Id; // 0 m_id uint32 Id; // 0 m_id

View file

@ -44,11 +44,12 @@ const char ChrClassesEntryfmt[]="nixsxxxixiiiii";
const char ChrRacesEntryfmt[]="nxixiixixxxxixsxxxxxixxx"; const char ChrRacesEntryfmt[]="nxixiixixxxxixsxxxxxixxx";
const char ChrClassesXPowerTypesfmt[]="nii"; const char ChrClassesXPowerTypesfmt[]="nii";
const char CinematicSequencesEntryfmt[] = "nxxxxxxxxx"; const char CinematicSequencesEntryfmt[] = "nxxxxxxxxx";
const char CreatureDisplayInfofmt[]="nxxifxxxxxxxxxxxx"; const char CreatureDisplayInfofmt[]="nixifxxxxxxxxxxxx";
const char CreatureDisplayInfoExtrafmt[] = "nixxxxxxxxxxxxxxxxxxx"; const char CreatureDisplayInfoExtrafmt[] = "nixxxxxxxxxxxxxxxxxxx";
const char CreatureFamilyfmt[]="nfifiiiiixsx"; const char CreatureFamilyfmt[]="nfifiiiiixsx";
const char CreatureModelDatafmt[] = "nxxxxxxxxxxxxxxffxxxxxxxxxxxxxx";
const char CreatureSpellDatafmt[] = "niiiixxxx"; const char CreatureSpellDatafmt[] = "niiiixxxx";
const char DestructibleModelDataFmt[] = "nixxxixxxxixxxxixxxxxxxx"; const char DestructibleModelDataFmt[] = "nixxxixxxxixxxxixxxxixxx";
const char DungeonEncounterfmt[]="niiiisxx"; const char DungeonEncounterfmt[]="niiiisxx";
const char CreatureTypefmt[]="nxx"; const char CreatureTypefmt[]="nxx";
const char CurrencyTypesfmt[]="nisxxxxiiix"; const char CurrencyTypesfmt[]="nisxxxxiiix";

View file

@ -856,14 +856,14 @@ void InitializeOpcodes()
//OPCODE(SMSG_SPLINE_SET_SWIM_BACK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(SMSG_SPLINE_SET_SWIM_BACK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
//OPCODE(SMSG_SPLINE_SET_TURN_RATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(SMSG_SPLINE_SET_TURN_RATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_SPLINE_MOVE_UNROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_UNROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
//OPCODE(SMSG_SPLINE_MOVE_FEATHER_FALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_FEATHER_FALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
//OPCODE(SMSG_SPLINE_MOVE_NORMAL_FALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_NORMAL_FALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_SPLINE_MOVE_SET_HOVER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_SET_HOVER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_SPLINE_MOVE_UNSET_HOVER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_UNSET_HOVER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_SPLINE_MOVE_WATER_WALK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_WATER_WALK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_SPLINE_MOVE_LAND_WALK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_LAND_WALK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_SPLINE_MOVE_START_SWIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_START_SWIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
//OPCODE(SMSG_SPLINE_MOVE_STOP_SWIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_STOP_SWIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_SPLINE_MOVE_SET_RUN_MODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_SET_RUN_MODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_SPLINE_MOVE_SET_WALK_MODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_SET_WALK_MODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
//OPCODE(CMSG_GM_NUKE_ACCOUNT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //OPCODE(CMSG_GM_NUKE_ACCOUNT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@ -1268,7 +1268,7 @@ void InitializeOpcodes()
OPCODE(SMSG_SERVER_FIRST_ACHIEVEMENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SERVER_FIRST_ACHIEVEMENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_PET_LEARNED_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_PET_LEARNED_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_PET_REMOVED_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_PET_REMOVED_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle ); OPCODE(CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle );
OPCODE(CMSG_HEARTH_AND_RESURRECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleHearthandResurrect ); OPCODE(CMSG_HEARTH_AND_RESURRECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleHearthandResurrect );
OPCODE(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_CRITERIA_DELETED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_CRITERIA_DELETED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
@ -1319,9 +1319,9 @@ void InitializeOpcodes()
//OPCODE(CMSG_START_BATTLEFIELD_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //OPCODE(CMSG_START_BATTLEFIELD_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//OPCODE(CMSG_END_BATTLEFIELD_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //OPCODE(CMSG_END_BATTLEFIELD_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//OPCODE(SMSG_COMPOUND_MOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(SMSG_COMPOUND_MOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_MOVE_GRAVITY_DISABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_MOVE_GRAVITY_DISABLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(CMSG_MOVE_GRAVITY_DISABLE_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); OPCODE(CMSG_MOVE_GRAVITY_DISABLE_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
OPCODE(SMSG_MOVE_GRAVITY_ENABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_MOVE_GRAVITY_ENABLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(CMSG_MOVE_GRAVITY_ENABLE_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); OPCODE(CMSG_MOVE_GRAVITY_ENABLE_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//OPCODE(MSG_MOVE_GRAVITY_CHNG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(MSG_MOVE_GRAVITY_CHNG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_SPLINE_MOVE_GRAVITY_DISABLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPLINE_MOVE_GRAVITY_DISABLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
@ -1392,7 +1392,7 @@ void InitializeOpcodes()
//OPCODE(SMSG_SEND_ALL_COMBAT_LOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(SMSG_SEND_ALL_COMBAT_LOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_OPEN_LFG_DUNGEON_FINDER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_OPEN_LFG_DUNGEON_FINDER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
OPCODE(SMSG_MOVE_SET_COLLISION_HGT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_MOVE_SET_COLLISION_HGT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
//OPCODE(CMSG_MOVE_SET_COLLISION_HGT_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); OPCODE(CMSG_MOVE_SET_COLLISION_HGT_ACK, STATUS_UNHANDLED,PROCESS_INPLACE, &WorldSession::Handle_NULL );
//OPCODE(MSG_MOVE_SET_COLLISION_HGT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(MSG_MOVE_SET_COLLISION_HGT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
//OPCODE(CMSG_CLEAR_RANDOM_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //OPCODE(CMSG_CLEAR_RANDOM_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//OPCODE(CMSG_CLEAR_HOLIDAY_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //OPCODE(CMSG_CLEAR_HOLIDAY_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );

View file

@ -840,8 +840,8 @@ enum Opcodes
SMSG_SPLINE_SET_SWIM_BACK_SPEED = 0x1303, SMSG_SPLINE_SET_SWIM_BACK_SPEED = 0x1303,
SMSG_SPLINE_SET_TURN_RATE = 0x1304, SMSG_SPLINE_SET_TURN_RATE = 0x1304,
SMSG_SPLINE_MOVE_UNROOT = 0x75B6, // 4.3.4 15595 SMSG_SPLINE_MOVE_UNROOT = 0x75B6, // 4.3.4 15595
SMSG_SPLINE_MOVE_FEATHER_FALL = 0x1306, SMSG_SPLINE_MOVE_FEATHER_FALL = 0x3DA5, // 4.3.4 15595
SMSG_SPLINE_MOVE_NORMAL_FALL = 0x1307, SMSG_SPLINE_MOVE_NORMAL_FALL = 0x38B2, // 4.3.4 15595
SMSG_SPLINE_MOVE_SET_HOVER = 0x14B6, // 4.3.4 15595 SMSG_SPLINE_MOVE_SET_HOVER = 0x14B6, // 4.3.4 15595
SMSG_SPLINE_MOVE_UNSET_HOVER = 0x7DA5, // 4.3.4 15595 SMSG_SPLINE_MOVE_UNSET_HOVER = 0x7DA5, // 4.3.4 15595
SMSG_SPLINE_MOVE_WATER_WALK = 0x50A2, // 4.3.4 15595 SMSG_SPLINE_MOVE_WATER_WALK = 0x50A2, // 4.3.4 15595
@ -1238,7 +1238,7 @@ enum Opcodes
CMSG_REMOVE_GLYPH = 0x148B, CMSG_REMOVE_GLYPH = 0x148B,
CMSG_DUMP_OBJECTS = 0x148C, CMSG_DUMP_OBJECTS = 0x148C,
SMSG_DUMP_OBJECTS_DATA = 0x148D, SMSG_DUMP_OBJECTS_DATA = 0x148D,
CMSG_DISMISS_CRITTER = 0x4227, CMSG_DISMISS_CRITTER = 0x4227, // 4.3.4 15595
SMSG_NOTIFY_DEST_LOC_SPELL_CAST = 0x148F, SMSG_NOTIFY_DEST_LOC_SPELL_CAST = 0x148F,
CMSG_AUCTION_LIST_PENDING_SALES = 0x2C17, // 4.3.4 15595 CMSG_AUCTION_LIST_PENDING_SALES = 0x2C17, // 4.3.4 15595
SMSG_AUCTION_LIST_PENDING_SALES = 0x6A27, // 4.3.4 15595 SMSG_AUCTION_LIST_PENDING_SALES = 0x6A27, // 4.3.4 15595
@ -1264,9 +1264,9 @@ enum Opcodes
CMSG_SET_BREATH = 0x14A5, CMSG_SET_BREATH = 0x14A5,
CMSG_QUERY_VEHICLE_STATUS = 0x14A6, CMSG_QUERY_VEHICLE_STATUS = 0x14A6,
SMSG_BATTLEGROUND_INFO_THROTTLED = 0x14A7, SMSG_BATTLEGROUND_INFO_THROTTLED = 0x14A7,
SMSG_SET_VEHICLE_REC_ID = 0x14A8, SMSG_SET_VEHICLE_REC_ID = 0x4115, // 4.3.4 15595
CMSG_RIDE_VEHICLE_INTERACT = 0x14A9, CMSG_RIDE_VEHICLE_INTERACT = 0x2705, // 4.3.4 15595
CMSG_CONTROLLER_EJECT_PASSENGER = 0x14AA, CMSG_CONTROLLER_EJECT_PASSENGER = 0x6927, // 4.3.4 15595
SMSG_PET_GUIDS = 0x2D26, // 4.3.4 15595 SMSG_PET_GUIDS = 0x2D26, // 4.3.4 15595
SMSG_CLIENTCACHE_VERSION = 0x2734, // 4.3.4 15595 SMSG_CLIENTCACHE_VERSION = 0x2734, // 4.3.4 15595
CMSG_CHANGE_GDF_ARENA_RATING = 0x14AD, CMSG_CHANGE_GDF_ARENA_RATING = 0x14AD,
@ -1376,7 +1376,7 @@ enum Opcodes
SMSG_SEND_ALL_COMBAT_LOG = 0x1515, SMSG_SEND_ALL_COMBAT_LOG = 0x1515,
SMSG_OPEN_LFG_DUNGEON_FINDER = 0x0412, // 4.3.4 15595 SMSG_OPEN_LFG_DUNGEON_FINDER = 0x0412, // 4.3.4 15595
SMSG_MOVE_SET_COLLISION_HGT = 0x11B0, // 4.3.4 15595 SMSG_MOVE_SET_COLLISION_HGT = 0x11B0, // 4.3.4 15595
CMSG_MOVE_SET_COLLISION_HGT_ACK = 0x1518, CMSG_MOVE_SET_COLLISION_HGT_ACK = 0x7114, // 4.3.4 15595
MSG_MOVE_SET_COLLISION_HGT = 0x1519, MSG_MOVE_SET_COLLISION_HGT = 0x1519,
CMSG_CLEAR_RANDOM_BG_WIN_TIME = 0x151A, CMSG_CLEAR_RANDOM_BG_WIN_TIME = 0x151A,
CMSG_CLEAR_HOLIDAY_BG_WIN_TIME = 0x151B, CMSG_CLEAR_HOLIDAY_BG_WIN_TIME = 0x151B,

View file

@ -451,7 +451,7 @@ enum SpellAttributesEx4
enum SpellAttributesEx5 enum SpellAttributesEx5
{ {
SPELL_ATTR_EX5_UNK0 = 0x00000001,// 0 SPELL_ATTR_EX5_CAN_CHANNEL_WHEN_MOVING = 0x00000001,// 0 don't interrupt channeling spells when moving
SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP = 0x00000002,// 1 not need reagents if UNIT_FLAG_PREPARATION SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP = 0x00000002,// 1 not need reagents if UNIT_FLAG_PREPARATION
SPELL_ATTR_EX5_UNK2 = 0x00000004,// 2 removed at enter arena (e.g. 31850 since 3.3.3) SPELL_ATTR_EX5_UNK2 = 0x00000004,// 2 removed at enter arena (e.g. 31850 since 3.3.3)
SPELL_ATTR_EX5_USABLE_WHILE_STUNNED = 0x00000008,// 3 usable while stunned SPELL_ATTR_EX5_USABLE_WHILE_STUNNED = 0x00000008,// 3 usable while stunned
@ -3792,4 +3792,14 @@ enum TeleportLocation
TELEPORT_LOCATION_BG_ENTRY_POINT = 1, TELEPORT_LOCATION_BG_ENTRY_POINT = 1,
}; };
// For Loot system
enum CreatureLootStatus
{
CREATURE_LOOT_STATUS_NONE = 0,
CREATURE_LOOT_STATUS_PICKPOCKETED = 1,
CREATURE_LOOT_STATUS_LOOTED = 2,
CREATURE_LOOT_STATUS_SKIN_AVAILABLE = 3,
CREATURE_LOOT_STATUS_SKINNED = 4
};
#endif #endif

View file

@ -677,6 +677,7 @@ class WorldSession
void HandleGossipHelloOpcode(WorldPacket& recvPacket); void HandleGossipHelloOpcode(WorldPacket& recvPacket);
void HandleGossipSelectOptionOpcode(WorldPacket& recvPacket); void HandleGossipSelectOptionOpcode(WorldPacket& recvPacket);
void HandleSpiritHealerActivateOpcode(WorldPacket& recvPacket); void HandleSpiritHealerActivateOpcode(WorldPacket& recvPacket);
void HandleReturnToGraveyardOpcode(WorldPacket& recvPacket);
void HandleNpcTextQueryOpcode(WorldPacket& recvPacket); void HandleNpcTextQueryOpcode(WorldPacket& recvPacket);
void HandleBinderActivateOpcode(WorldPacket& recvPacket); void HandleBinderActivateOpcode(WorldPacket& recvPacket);
void HandleListStabledPetsOpcode(WorldPacket& recvPacket); void HandleListStabledPetsOpcode(WorldPacket& recvPacket);

View file

@ -232,6 +232,7 @@ bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
return false; return false;
normalizeString(passwd); normalizeString(passwd);
normalizeString(username);
QueryResult* result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%u' AND sha_pass_hash='%s'", accid, CalculateShaPassHash(username, passwd).c_str()); QueryResult* result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%u' AND sha_pass_hash='%s'", accid, CalculateShaPassHash(username, passwd).c_str());
if (result) if (result)

View file

@ -40,15 +40,22 @@ void WorldSession::HandleInspectArenaTeamsOpcode(WorldPacket& recv_data)
recv_data >> guid; recv_data >> guid;
DEBUG_LOG("Inspect Arena stats %s", guid.GetString().c_str()); DEBUG_LOG("Inspect Arena stats %s", guid.GetString().c_str());
if (Player* plr = sObjectMgr.GetPlayer(guid)) Player* player = sObjectMgr.GetPlayer(guid);
if (!player)
return;
if (!_player->IsWithinDistInMap(player, INSPECT_DISTANCE, false))
return;
if (_player->IsHostileTo(player))
return;
for (uint8 i = 0; i < MAX_ARENA_SLOT; ++i)
{ {
for (uint8 i = 0; i < MAX_ARENA_SLOT; ++i) if (uint32 a_id = player->GetArenaTeamId(i))
{ {
if (uint32 a_id = plr->GetArenaTeamId(i)) if (ArenaTeam* arenaTeam = sObjectMgr.GetArenaTeamById(a_id))
{ arenaTeam->InspectStats(this, player->GetObjectGuid());
if (ArenaTeam* at = sObjectMgr.GetArenaTeamById(a_id))
at->InspectStats(this, plr->GetObjectGuid());
}
} }
} }
} }

View file

@ -311,7 +311,7 @@ ChatCommand* ChatHandler::getCommandTable()
{ "setphase", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectPhaseCommand, "", NULL }, { "setphase", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectPhaseCommand, "", NULL },
{ "target", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTargetCommand, "", NULL }, { "target", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTargetCommand, "", NULL },
{ "turn", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTurnCommand, "", NULL }, { "turn", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTurnCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL } { nullptr, 0, false, NULL, "", NULL }
}; };
static ChatCommand guildCommandTable[] = static ChatCommand guildCommandTable[] =
@ -413,6 +413,7 @@ ChatCommand* ChatHandler::getCommandTable()
{ "loadedtiles", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapLoadedTilesCommand, "", NULL }, { "loadedtiles", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapLoadedTilesCommand, "", NULL },
{ "stats", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapStatsCommand, "", NULL }, { "stats", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapStatsCommand, "", NULL },
{ "testarea", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapTestArea, "", NULL }, { "testarea", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapTestArea, "", NULL },
{ "testheight", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapTestHeight, "", NULL },
{ "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMmap, "", NULL }, { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMmap, "", NULL },
{ NULL, 0, false, NULL, "", NULL } { NULL, 0, false, NULL, "", NULL }
}; };

View file

@ -639,6 +639,7 @@ class ChatHandler
bool HandleMmapStatsCommand(char* args); bool HandleMmapStatsCommand(char* args);
bool HandleMmap(char* args); bool HandleMmap(char* args);
bool HandleMmapTestArea(char* args); bool HandleMmapTestArea(char* args);
bool HandleMmapTestHeight(char* args);
//! Development Commands //! Development Commands
bool HandleSaveAllCommand(char* args); bool HandleSaveAllCommand(char* args);

View file

@ -173,7 +173,14 @@ void CreatureLinkingMgr::LoadFromDB()
delete result; delete result;
} }
// This function is used to check if a DB-Entry is valid /** This function is used to check if a DB-Entry is valid
*
* @param byEntry: is the first parameter of the function a npc entry or a npc guid?
* @param slaveEntry: dependend on byEntry param this is either the slave's npc-entry or the npc-guid
* @param pTmp: Information about the CreatureLinking of the npc. Note that this information may be changed in some cases
*
* In case of checking by entry and in case of linked spawning and searchRange == 0, pTmp will be changed to keep information about the (unique!) master's db-guid
*/
bool CreatureLinkingMgr::IsLinkingEntryValid(uint32 slaveEntry, CreatureLinkingInfo* pTmp, bool byEntry) bool CreatureLinkingMgr::IsLinkingEntryValid(uint32 slaveEntry, CreatureLinkingInfo* pTmp, bool byEntry)
{ {
// Basic checks first // Basic checks first
@ -238,14 +245,22 @@ bool CreatureLinkingMgr::IsLinkingEntryValid(uint32 slaveEntry, CreatureLinkingI
// Check for uniqueness of mob whom is followed, on whom spawning is dependend // Check for uniqueness of mob whom is followed, on whom spawning is dependend
if (pTmp->searchRange == 0 && pTmp->linkingFlag & (FLAG_FOLLOW | FLAG_CANT_SPAWN_IF_BOSS_DEAD | FLAG_CANT_SPAWN_IF_BOSS_ALIVE)) if (pTmp->searchRange == 0 && pTmp->linkingFlag & (FLAG_FOLLOW | FLAG_CANT_SPAWN_IF_BOSS_DEAD | FLAG_CANT_SPAWN_IF_BOSS_ALIVE))
{ {
// Painfully slow, needs better idea QueryResult* result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id=%u AND map=%u LIMIT 2", pTmp->masterId, pTmp->mapId);
QueryResult* result = WorldDatabase.PQuery("SELECT COUNT(guid) FROM creature WHERE id=%u AND map=%u", pTmp->masterId, pTmp->mapId); if (!result)
if (result)
{ {
if ((*result)[0].GetUInt32() > 1) sLog.outErrorDb("`creature_linking_template` has FLAG_FOLLOW, but no master, (entry: %u, map: %u, master: %u)", slaveEntry, pTmp->mapId, pTmp->masterId);
sLog.outErrorDb("`creature_linking_template` has FLAG_FOLLOW, but non unique master, (entry: %u, map: %u, master: %u)", slaveEntry, pTmp->mapId, pTmp->masterId); return false;
delete result;
} }
if (result->GetRowCount() > 1)
{
sLog.outErrorDb("`creature_linking_template` has FLAG_FOLLOW, but non unique master, (entry: %u, map: %u, master: %u)", slaveEntry, pTmp->mapId, pTmp->masterId);
delete result;
return false;
}
Field* fields = result->Fetch();
pTmp->masterDBGuid = fields[0].GetUInt32();
delete result;
} }
} }
@ -265,7 +280,7 @@ enum EventMask
}; };
// This functions checks if the NPC has linked NPCs for dynamic action // This functions checks if the NPC has linked NPCs for dynamic action
bool CreatureLinkingMgr::IsLinkedEventTrigger(Creature* pCreature) bool CreatureLinkingMgr::IsLinkedEventTrigger(Creature* pCreature) const
{ {
// Entry case // Entry case
if (m_eventTriggers.find(pCreature->GetEntry()) != m_eventTriggers.end()) if (m_eventTriggers.find(pCreature->GetEntry()) != m_eventTriggers.end())
@ -284,37 +299,43 @@ bool CreatureLinkingMgr::IsLinkedEventTrigger(Creature* pCreature)
// This function check if the NPC is a master to other NPCs // This function check if the NPC is a master to other NPCs
// return true only for masters stored by entry - this prevents adding them to master-holder maps // return true only for masters stored by entry - this prevents adding them to master-holder maps
bool CreatureLinkingMgr::IsLinkedMaster(Creature* pCreature) bool CreatureLinkingMgr::IsLinkedMaster(Creature* pCreature) const
{ {
return m_eventTriggers.find(pCreature->GetEntry()) != m_eventTriggers.end(); return m_eventTriggers.find(pCreature->GetEntry()) != m_eventTriggers.end();
} }
// This function checks if the spawning of this NPC is dependend on other NPCs // This function checks if the spawning of this NPC is dependend on other NPCs
bool CreatureLinkingMgr::IsSpawnedByLinkedMob(Creature* pCreature) bool CreatureLinkingMgr::IsSpawnedByLinkedMob(Creature* pCreature) const
{
return IsSpawnedByLinkedMob(GetLinkedTriggerInformation(pCreature));
}
bool CreatureLinkingMgr::IsSpawnedByLinkedMob(CreatureLinkingInfo const* pInfo) const
{ {
CreatureLinkingInfo const* pInfo = CreatureLinkingMgr::GetLinkedTriggerInformation(pCreature);
return pInfo && pInfo->linkingFlag & (FLAG_CANT_SPAWN_IF_BOSS_DEAD | FLAG_CANT_SPAWN_IF_BOSS_ALIVE) && (pInfo->masterDBGuid || pInfo->searchRange); return pInfo && pInfo->linkingFlag & (FLAG_CANT_SPAWN_IF_BOSS_DEAD | FLAG_CANT_SPAWN_IF_BOSS_ALIVE) && (pInfo->masterDBGuid || pInfo->searchRange);
} }
// This gives the information of a linked NPC (describes action when its ActionTrigger triggers) // This gives the information of a linked NPC (describes action when its ActionTrigger triggers)
// Depends of the map // Depends of the map
CreatureLinkingInfo const* CreatureLinkingMgr::GetLinkedTriggerInformation(Creature* pCreature) CreatureLinkingInfo const* CreatureLinkingMgr::GetLinkedTriggerInformation(Creature* pCreature) const
{
return GetLinkedTriggerInformation(pCreature->GetEntry(), pCreature->GetGUIDLow(), pCreature->GetMapId());
}
CreatureLinkingInfo const* CreatureLinkingMgr::GetLinkedTriggerInformation(uint32 entry, uint32 lowGuid, uint32 mapId) const
{ {
// guid case // guid case
CreatureLinkingMapBounds bounds = m_creatureLinkingGuidMap.equal_range(pCreature->GetGUIDLow()); CreatureLinkingMapBounds bounds = m_creatureLinkingGuidMap.equal_range(lowGuid);
for (CreatureLinkingMap::const_iterator iter = bounds.first; iter != bounds.second; ++iter) for (CreatureLinkingMap::const_iterator iter = bounds.first; iter != bounds.second;)
return &(iter->second); return &(iter->second);
// entry case // entry case
bounds = m_creatureLinkingMap.equal_range(pCreature->GetEntry()); bounds = m_creatureLinkingMap.equal_range(entry);
for (CreatureLinkingMap::const_iterator iter = bounds.first; iter != bounds.second; ++iter) for (CreatureLinkingMap::const_iterator iter = bounds.first; iter != bounds.second; ++iter)
{ {
if (iter->second.mapId == pCreature->GetMapId()) if (iter->second.mapId == mapId)
return &(iter->second); return &(iter->second);
} }
return NULL; return nullptr;
} }
// Function to add slave-NPCs to the holder // Function to add slave-NPCs to the holder
@ -384,7 +405,7 @@ void CreatureLinkingHolder::AddMasterToHolder(Creature* pCreature)
// Check, if already stored // Check, if already stored
BossGuidMapBounds bounds = m_masterGuid.equal_range(pCreature->GetEntry()); BossGuidMapBounds bounds = m_masterGuid.equal_range(pCreature->GetEntry());
for (BossGuidMap::iterator itr = bounds.first; itr != bounds.second; ++itr) for (BossGuidMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
if (itr->second == pCreature->GetObjectGuid()) if (itr->second == pCreature->GetObjectGuid())
return; // Already added return; // Already added
@ -432,11 +453,11 @@ void CreatureLinkingHolder::DoCreatureLinkingEvent(CreatureLinkingEvent eventTyp
{ {
if (pInfo->linkingFlag & reverseEventFlagFilter) if (pInfo->linkingFlag & reverseEventFlagFilter)
{ {
Creature* pMaster = NULL; Creature* pMaster = nullptr;
if (pInfo->mapId != INVALID_MAP_ID) // entry case if (pInfo->mapId != INVALID_MAP_ID) // entry case
{ {
BossGuidMapBounds finds = m_masterGuid.equal_range(pInfo->masterId); BossGuidMapBounds finds = m_masterGuid.equal_range(pInfo->masterId);
for (BossGuidMap::iterator itr = finds.first; itr != finds.second; ++itr) for (BossGuidMap::const_iterator itr = finds.first; itr != finds.second; ++itr)
{ {
pMaster = pSource->GetMap()->GetCreature(itr->second); pMaster = pSource->GetMap()->GetCreature(itr->second);
if (pMaster && IsSlaveInRangeOfBoss(pSource, pMaster, pInfo->searchRange)) if (pMaster && IsSlaveInRangeOfBoss(pSource, pMaster, pInfo->searchRange))
@ -589,49 +610,93 @@ void CreatureLinkingHolder::SetFollowing(Creature* pWho, Creature* pWhom)
} }
// Function to check if a slave belongs to a boss by range-issue // Function to check if a slave belongs to a boss by range-issue
bool CreatureLinkingHolder::IsSlaveInRangeOfBoss(Creature* pSlave, Creature* pBoss, uint16 searchRange) bool CreatureLinkingHolder::IsSlaveInRangeOfBoss(Creature const* pSlave, Creature const* pBoss, uint16 searchRange) const
{
float sX, sY, sZ;
pSlave->GetRespawnCoord(sX, sY, sZ);
return IsSlaveInRangeOfBoss(pBoss, sX, sY, searchRange);
}
bool CreatureLinkingHolder::IsSlaveInRangeOfBoss(Creature const* pBoss, float sX, float sY, uint16 searchRange) const
{ {
if (!searchRange) if (!searchRange)
return true; return true;
// Do some calculations // Do some calculations
float sX, sY, sZ, mX, mY, mZ; float mX, mY, mZ, dx, dy;
pSlave->GetRespawnCoord(sX, sY, sZ);
pBoss->GetRespawnCoord(mX, mY, mZ); pBoss->GetRespawnCoord(mX, mY, mZ);
float dx, dy;
dx = sX - mX; dx = sX - mX;
dy = sY - mY; dy = sY - mY;
return dx * dx + dy * dy < searchRange * searchRange; return dx * dx + dy * dy < searchRange * searchRange;
} }
// helper function to check if a lowguid can respawn
bool CreatureLinkingHolder::IsRespawnReady(uint32 dbLowGuid, Map* _map) const
{
time_t respawnTime = _map->GetPersistentState()->GetCreatureRespawnTime(dbLowGuid);
return (!respawnTime || respawnTime <= time(nullptr)) && CanSpawn(dbLowGuid, _map, nullptr, 0.0f, 0.0f);
}
// Function to check if a passive spawning condition is met // Function to check if a passive spawning condition is met
bool CreatureLinkingHolder::CanSpawn(Creature* pCreature) bool CreatureLinkingHolder::CanSpawn(Creature* pCreature) const
{ {
CreatureLinkingInfo const* pInfo = sCreatureLinkingMgr.GetLinkedTriggerInformation(pCreature); CreatureLinkingInfo const* pInfo = sCreatureLinkingMgr.GetLinkedTriggerInformation(pCreature);
if (!pInfo) if (!pInfo)
return true; return true;
float sx, sy, sz;
pCreature->GetRespawnCoord(sx, sy, sz);
return CanSpawn(0, pCreature->GetMap(), pInfo, sx, sy);
}
/** Worker function to check if a spawning condition is met
*
* This function is used directly from above function, and for recursive use
* in case of recursive use it is used only on _map with information of lowGuid.
*
* @param lowGuid (only relevant in case of recursive uses) -- db-guid of the npc that is checked
* @param _map Map on which things are checked
* @param pInfo (only shipped in case of initial use) -- used as marker of first use, also in first use filled directly
* @param sx, sy (spawn position of the checked npc with initial use)
*/
bool CreatureLinkingHolder::CanSpawn(uint32 lowGuid, Map* _map, CreatureLinkingInfo const* pInfo, float sx, float sy) const
{
if (!pInfo) // Prepare data for recursive use
{
CreatureData const* data = sObjectMgr.GetCreatureData(lowGuid);
if (!data)
return true;
pInfo = sCreatureLinkingMgr.GetLinkedTriggerInformation(data->id, lowGuid, data->mapid);
if (!pInfo)
return true;
// Has lowGuid npc actually spawning linked?
if (!sCreatureLinkingMgr.IsSpawnedByLinkedMob(pInfo))
return true;
sx = data->posX; // Fill position data
sy = data->posY;
}
if (pInfo->searchRange == 0) // Map wide case if (pInfo->searchRange == 0) // Map wide case
{ {
if (!pInfo->masterDBGuid) if (!pInfo->masterDBGuid)
return false; // This should never happen return false; // This should never happen
if (pInfo->linkingFlag & FLAG_CANT_SPAWN_IF_BOSS_DEAD) if (pInfo->linkingFlag & FLAG_CANT_SPAWN_IF_BOSS_DEAD)
return pCreature->GetMap()->GetPersistentState()->GetCreatureRespawnTime(pInfo->masterDBGuid) == 0; return IsRespawnReady(pInfo->masterDBGuid, _map);
else if (pInfo->linkingFlag & FLAG_CANT_SPAWN_IF_BOSS_ALIVE) else if (pInfo->linkingFlag & FLAG_CANT_SPAWN_IF_BOSS_ALIVE)
return pCreature->GetMap()->GetPersistentState()->GetCreatureRespawnTime(pInfo->masterDBGuid) > 0; return !IsRespawnReady(pInfo->masterDBGuid, _map);
else else
return true; return true;
} }
// Search for nearby master // Search for nearby master
BossGuidMapBounds finds = m_masterGuid.equal_range(pInfo->masterId); BossGuidMapBounds finds = m_masterGuid.equal_range(pInfo->masterId);
for (BossGuidMap::iterator itr = finds.first; itr != finds.second; ++itr) for (BossGuidMap::const_iterator itr = finds.first; itr != finds.second; ++itr)
{ {
Creature* pMaster = pCreature->GetMap()->GetCreature(itr->second); Creature* pMaster = _map->GetCreature(itr->second);
if (pMaster && IsSlaveInRangeOfBoss(pCreature, pMaster, pInfo->searchRange)) if (pMaster && IsSlaveInRangeOfBoss(pMaster, sx, sy, pInfo->searchRange))
{ {
if (pInfo->linkingFlag & FLAG_CANT_SPAWN_IF_BOSS_DEAD) if (pInfo->linkingFlag & FLAG_CANT_SPAWN_IF_BOSS_DEAD)
return pMaster->IsAlive(); return pMaster->IsAlive();
@ -652,11 +717,11 @@ bool CreatureLinkingHolder::TryFollowMaster(Creature* pCreature)
if (!pInfo || !(pInfo->linkingFlag & FLAG_FOLLOW)) if (!pInfo || !(pInfo->linkingFlag & FLAG_FOLLOW))
return false; return false;
Creature* pMaster = NULL; Creature* pMaster = nullptr;
if (pInfo->mapId != INVALID_MAP_ID) // entry case if (pInfo->mapId != INVALID_MAP_ID) // entry case
{ {
BossGuidMapBounds finds = m_masterGuid.equal_range(pInfo->masterId); BossGuidMapBounds finds = m_masterGuid.equal_range(pInfo->masterId);
for (BossGuidMap::iterator itr = finds.first; itr != finds.second; ++itr) for (BossGuidMap::const_iterator itr = finds.first; itr != finds.second; ++itr)
{ {
pMaster = pCreature->GetMap()->GetCreature(itr->second); pMaster = pCreature->GetMap()->GetCreature(itr->second);
if (pMaster && IsSlaveInRangeOfBoss(pCreature, pMaster, pInfo->searchRange)) if (pMaster && IsSlaveInRangeOfBoss(pCreature, pMaster, pInfo->searchRange))

View file

@ -48,6 +48,7 @@
class Unit; class Unit;
class Creature; class Creature;
class Map;
// enum on which Events an action for linked NPCs can trigger // enum on which Events an action for linked NPCs can trigger
enum CreatureLinkingEvent enum CreatureLinkingEvent
@ -111,17 +112,19 @@ class CreatureLinkingMgr
public: // Accessors public: // Accessors
// This functions checks if the NPC triggers actions for other NPCs // This functions checks if the NPC triggers actions for other NPCs
bool IsLinkedEventTrigger(Creature* pCreature); bool IsLinkedEventTrigger(Creature* pCreature) const;
// This function checks if the NPC is a master NPC. // This function checks if the NPC is a master NPC.
bool IsLinkedMaster(Creature* pCreature); bool IsLinkedMaster(Creature* pCreature) const;
// This function checks if the spawning of this NPC is dependend on other NPCs // This function checks if the spawning of this NPC is dependend on other NPCs
bool IsSpawnedByLinkedMob(Creature* pCreature); bool IsSpawnedByLinkedMob(Creature* pCreature) const;
bool IsSpawnedByLinkedMob(CreatureLinkingInfo const* pInfo) const;
// This gives the information of a linked NPC (describes action when its ActionTrigger triggers) // This gives the information of a linked NPC (describes action when its ActionTrigger triggers)
// Depends of the map // Depends of the map
CreatureLinkingInfo const* GetLinkedTriggerInformation(Creature* pCreature); CreatureLinkingInfo const* GetLinkedTriggerInformation(Creature* pCreature) const;
CreatureLinkingInfo const* GetLinkedTriggerInformation(uint32 entry, uint32 lowGuid, uint32 mapId) const;
private: private:
typedef std::multimap < uint32 /*slaveEntry*/, CreatureLinkingInfo > CreatureLinkingMap; typedef std::multimap < uint32 /*slaveEntry*/, CreatureLinkingInfo > CreatureLinkingMap;
@ -162,7 +165,7 @@ class CreatureLinkingHolder
void DoCreatureLinkingEvent(CreatureLinkingEvent eventType, Creature* pSource, Unit* pEnemy = NULL); void DoCreatureLinkingEvent(CreatureLinkingEvent eventType, Creature* pSource, Unit* pEnemy = NULL);
// Function to check if a passive spawning condition is met // Function to check if a passive spawning condition is met
bool CanSpawn(Creature* pCreature); bool CanSpawn(Creature* pCreature) const;
// This function lets a slave refollow his master // This function lets a slave refollow his master
bool TryFollowMaster(Creature* pCreature); bool TryFollowMaster(Creature* pCreature);
@ -185,7 +188,7 @@ class CreatureLinkingHolder
typedef std::multimap < uint32 /*masterEntryOrGuid*/, InfoAndGuids > HolderMap; typedef std::multimap < uint32 /*masterEntryOrGuid*/, InfoAndGuids > HolderMap;
typedef std::pair<HolderMap::iterator, HolderMap::iterator> HolderMapBounds; typedef std::pair<HolderMap::iterator, HolderMap::iterator> HolderMapBounds;
typedef std::multimap < uint32 /*Entry*/, ObjectGuid > BossGuidMap; typedef std::multimap < uint32 /*Entry*/, ObjectGuid > BossGuidMap;
typedef std::pair<BossGuidMap::iterator, BossGuidMap::iterator> BossGuidMapBounds; typedef std::pair<BossGuidMap::const_iterator, BossGuidMap::const_iterator> BossGuidMapBounds;
// Helper function, to process a slave list // Helper function, to process a slave list
void ProcessSlaveGuidList(CreatureLinkingEvent eventType, Creature* pSource, uint32 flag, uint16 searchRange, GuidList& slaveGuidList, Unit* pEnemy); void ProcessSlaveGuidList(CreatureLinkingEvent eventType, Creature* pSource, uint32 flag, uint16 searchRange, GuidList& slaveGuidList, Unit* pEnemy);
@ -194,7 +197,12 @@ class CreatureLinkingHolder
// Helper function to set following // Helper function to set following
void SetFollowing(Creature* pWho, Creature* pWhom); void SetFollowing(Creature* pWho, Creature* pWhom);
// Helper function to return if a slave is in range of a boss // Helper function to return if a slave is in range of a boss
bool IsSlaveInRangeOfBoss(Creature* pSlave, Creature* pBoss, uint16 searchRange); bool IsSlaveInRangeOfBoss(Creature const* pSlave, Creature const* pBoss, uint16 searchRange) const;
bool IsSlaveInRangeOfBoss(Creature const* pBoss, float slaveX, float slaveY, uint16 searchRange) const;
// Another helper function
bool IsRespawnReady(uint32 dbLowGuid, Map* _map) const;
// Helper function for recursive spawning-checks of an additional linked
bool CanSpawn(uint32 lowGuid, Map* _map, CreatureLinkingInfo const* pInfo, float sx, float sy) const;
// Storage of Data (boss, flag, searchRange, GuidList) for action triggering // Storage of Data (boss, flag, searchRange, GuidList) for action triggering
HolderMap m_holderMap; HolderMap m_holderMap;

View file

@ -174,7 +174,7 @@ namespace MaNGOS
inline bool IsValidMapCoord(float c) inline bool IsValidMapCoord(float c)
{ {
return finite(c) && (std::fabs(c) <= MAP_HALFSIZE - 0.5); return std::isfinite(c) && (std::fabs(c) <= MAP_HALFSIZE - 0.5);
} }
inline bool IsValidMapCoord(float x, float y) inline bool IsValidMapCoord(float x, float y)
@ -184,12 +184,12 @@ namespace MaNGOS
inline bool IsValidMapCoord(float x, float y, float z) inline bool IsValidMapCoord(float x, float y, float z)
{ {
return IsValidMapCoord(x, y) && finite(z); return IsValidMapCoord(x, y) && std::isfinite(z);
} }
inline bool IsValidMapCoord(float x, float y, float z, float o) inline bool IsValidMapCoord(float x, float y, float z, float o)
{ {
return IsValidMapCoord(x, y, z) && finite(o); return IsValidMapCoord(x, y, z) && std::isfinite(o);
} }
} }
#endif #endif

View file

@ -42,6 +42,9 @@ char const* MAP_AREA_MAGIC = "AREA";
char const* MAP_HEIGHT_MAGIC = "MHGT"; char const* MAP_HEIGHT_MAGIC = "MHGT";
char const* MAP_LIQUID_MAGIC = "MLIQ"; char const* MAP_LIQUID_MAGIC = "MLIQ";
static uint16 holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 };
static uint16 holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
GridMap::GridMap() GridMap::GridMap()
{ {
m_flags = 0; m_flags = 0;
@ -1061,6 +1064,23 @@ bool TerrainInfo::IsInWater(float x, float y, float pZ, GridMapLiquidData* data)
return false; return false;
} }
// check if creature is in water and have enough space to swim
bool TerrainInfo::IsSwimmable(float x, float y, float pZ, float radius /*= 1.5f*/, GridMapLiquidData* data /*= 0*/) const
{
// Check surface in x, y point for liquid
if (const_cast<TerrainInfo*>(this)->GetGrid(x, y))
{
GridMapLiquidData liquid_status;
GridMapLiquidData* liquid_ptr = data ? data : &liquid_status;
if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr))
{
if (liquid_ptr->level - liquid_ptr->depth_level > radius) // is unit have enough space to swim
return true;
}
}
return false;
}
bool TerrainInfo::IsUnderWater(float x, float y, float z) const bool TerrainInfo::IsUnderWater(float x, float y, float z) const
{ {
if (const_cast<TerrainInfo*>(this)->GetGrid(x, y)) if (const_cast<TerrainInfo*>(this)->GetGrid(x, y))

View file

@ -231,6 +231,7 @@ class TerrainInfo : public Referencable<AtomicLong>
float GetWaterLevel(float x, float y, float z, float* pGround = NULL) const; float GetWaterLevel(float x, float y, float z, float* pGround = NULL) const;
float GetWaterOrGroundLevel(float x, float y, float z, float* pGround = NULL, bool swim = false) const; float GetWaterOrGroundLevel(float x, float y, float z, float* pGround = NULL, bool swim = false) const;
bool IsInWater(float x, float y, float z, GridMapLiquidData* data = 0) const; bool IsInWater(float x, float y, float z, GridMapLiquidData* data = 0) const;
bool IsSwimmable(float x, float y, float pZ, float radius = 1.5f, GridMapLiquidData* data = nullptr) const;
bool IsUnderWater(float x, float y, float z) const; bool IsUnderWater(float x, float y, float z) const;
GridMapLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData* data = 0) const; GridMapLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData* data = 0) const;

View file

@ -57,7 +57,9 @@ enum LootMethod
ROUND_ROBIN = 1, ROUND_ROBIN = 1,
MASTER_LOOT = 2, MASTER_LOOT = 2,
GROUP_LOOT = 3, GROUP_LOOT = 3,
NEED_BEFORE_GREED = 4 NEED_BEFORE_GREED = 4,
NOT_GROUP_TYPE_LOOT = 5 // internal use only
}; };
enum RollVote enum RollVote

View file

@ -71,7 +71,7 @@ bool WorldSession::CheckMailBox(ObjectGuid guid)
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!creature) if (!creature)
{ {
DEBUG_LOG("%s not found or %s can't interact with him.", creature->GetGuidStr().c_str(), GetPlayer()->GetGuidStr().c_str()); DEBUG_LOG("%s not found or %s can't interact with him.", guid.GetString().c_str(), GetPlayer()->GetGuidStr().c_str());
return false; return false;
} }

View file

@ -298,12 +298,15 @@ bool Map::EnsureGridLoaded(const Cell& cell)
return false; return false;
} }
void Map::LoadGrid(const Cell& cell, bool no_unload) void Map::ForceLoadGrid(float x, float y)
{ {
EnsureGridLoaded(cell); if (!IsLoaded(x, y))
{
if (no_unload) CellPair p = MaNGOS::ComputeCellPair(x, y);
Cell cell(p);
EnsureGridLoadedAtEnter(cell);
getNGrid(cell.GridX(), cell.GridY())->setUnloadExplicitLock(true); getNGrid(cell.GridX(), cell.GridY())->setUnloadExplicitLock(true);
}
} }
bool Map::Add(Player* player) bool Map::Add(Player* player)
@ -2116,6 +2119,61 @@ bool Map::GetHitPosition(float srcX, float srcY, float srcZ, float& destX, float
return result0 || result1; return result0 || result1;
} }
// Find an height within a reasonable range of provided Z. This method may fail so we have to handle that case.
bool Map::GetHeightInRange(uint32 phasemask, float x, float y, float& z, float maxSearchDist /*= 4.0f*/) const
{
float height, vmapHeight, mapHeight;
vmapHeight = VMAP_INVALID_HEIGHT_VALUE;
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
if (!vmgr->isLineOfSightCalcEnabled())
vmgr = nullptr;
if (vmgr)
{
// pure vmap search
vmapHeight = vmgr->getHeight(i_id, x, y, z + 2.0f, maxSearchDist + 2.0f);
}
// find raw height from .map file on X,Y coordinates
if (GridMap* gmap = const_cast<TerrainInfo*>(m_TerrainData)->GetGrid(x, y)) // TODO:: find a way to remove that const_cast
mapHeight = gmap->getHeight(x, y);
float diffMaps = fabs(fabs(z) - fabs(mapHeight));
float diffVmaps = fabs(fabs(z) - fabs(vmapHeight));
if (diffVmaps < maxSearchDist)
{
if (diffMaps < maxSearchDist)
{
// well we simply have to take the highest as normally there we cannot be on top of cavern is maxSearchDist is not too big
if (vmapHeight > mapHeight)
height = vmapHeight;
else
height = mapHeight;
//sLog.outString("vmap %5.4f, map %5.4f, height %5.4f", vmapHeight, mapHeight, height);
}
else
{
//sLog.outString("vmap %5.4f", vmapHeight);
height = vmapHeight;
}
}
else
{
if (diffMaps < maxSearchDist)
{
//sLog.outString("map %5.4f", mapHeight);
height = mapHeight;
}
else
return false;
}
z = std::max<float>(height, m_dyn_tree.getHeight(x, y, height + 1.0f, maxSearchDist, phasemask));
return true;
}
float Map::GetHeight(uint32 phasemask, float x, float y, float z) const float Map::GetHeight(uint32 phasemask, float x, float y, float z) const
{ {
float staticHeight = m_TerrainData->GetHeightStatic(x, y, z); float staticHeight = m_TerrainData->GetHeightStatic(x, y, z);

View file

@ -157,7 +157,7 @@ class Map : public GridRefManager<NGridType>
bool GetUnloadLock(const GridPair& p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } bool GetUnloadLock(const GridPair& p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); }
void SetUnloadLock(const GridPair& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } void SetUnloadLock(const GridPair& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); }
void LoadGrid(const Cell& cell, bool no_unload = false); void ForceLoadGrid(float x, float y);
bool UnloadGrid(const uint32& x, const uint32& y, bool pForce); bool UnloadGrid(const uint32& x, const uint32& y, bool pForce);
virtual void UnloadAll(bool pForce); virtual void UnloadAll(bool pForce);
@ -194,7 +194,6 @@ class Map : public GridRefManager<NGridType>
MapDifficultyEntry const* GetMapDifficulty() const; // dependent from map difficulty MapDifficultyEntry const* GetMapDifficulty() const; // dependent from map difficulty
bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); } bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); }
// NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable
bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); } bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); }
bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); }
bool IsHeroic() const { return IsRaid() ? i_spawnMode >= RAID_DIFFICULTY_10MAN_HEROIC : i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; } bool IsHeroic() const { return IsRaid() ? i_spawnMode >= RAID_DIFFICULTY_10MAN_HEROIC : i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; }
@ -203,6 +202,7 @@ class Map : public GridRefManager<NGridType>
bool IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); } bool IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); }
bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); }
bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); } bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); }
bool IsContinent() const { return i_mapEntry && i_mapEntry->IsContinent(); }
// can't be NULL for loaded map // can't be NULL for loaded map
MapPersistentState* GetPersistentState() const { return m_persistentState; } MapPersistentState* GetPersistentState() const { return m_persistentState; }

View file

@ -92,30 +92,30 @@ void MapManager::InitializeVisibilityDistanceInfo()
(*iter).second->InitVisibilityDistance(); (*iter).second->InitVisibilityDistance();
} }
/// @param id - MapId of the to be created map. @param obj WorldObject for which the map is to be created. Must be player for Instancable maps.
Map* MapManager::CreateMap(uint32 id, const WorldObject* obj) Map* MapManager::CreateMap(uint32 id, const WorldObject* obj)
{ {
MANGOS_ASSERT(obj);
// if(!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId());
Guard _guard(*this); Guard _guard(*this);
Map* m = NULL; Map* m = nullptr;
const MapEntry* entry = sMapStore.LookupEntry(id); const MapEntry* entry = sMapStore.LookupEntry(id);
if (!entry) if (!entry)
return NULL; return nullptr;
if (entry->Instanceable()) if (entry->Instanceable())
{ {
MANGOS_ASSERT(obj->GetTypeId() == TYPEID_PLAYER); MANGOS_ASSERT(obj && obj->GetTypeId() == TYPEID_PLAYER);
// create DungeonMap object // create DungeonMap object
if (obj->GetTypeId() == TYPEID_PLAYER) m = CreateInstance(id, (Player*)obj);
m = CreateInstance(id, (Player*)obj); // Load active objects for this map
sObjectMgr.LoadActiveEntities(m);
} }
else else
{ {
// create regular non-instanceable map // create regular non-instanceable map
m = FindMap(id); m = FindMap(id);
if (m == NULL) if (m == nullptr)
{ {
m = new WorldMap(id, i_gridCleanUpDelay); m = new WorldMap(id, i_gridCleanUpDelay);
// add map into container // add map into container

View file

@ -94,7 +94,6 @@ class MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::ClassLevelLockab
i_timer.Reset(); i_timer.Reset();
} }
// void LoadGrid(int mapid, int instId, float x, float y, const WorldObject* obj, bool no_unload = false);
void UnloadAll(); void UnloadAll();
static bool ExistMapAndVMap(uint32 mapid, float x, float y); static bool ExistMapAndVMap(uint32 mapid, float x, float y);

View file

@ -280,7 +280,6 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPacket & /*recv_data*/)
// Can not logout if... // Can not logout if...
if (GetPlayer()->IsInCombat() || //...is in combat if (GetPlayer()->IsInCombat() || //...is in combat
GetPlayer()->duel || //...is in Duel
//...is jumping ...is falling //...is jumping ...is falling
GetPlayer()->m_movementInfo.HasMovementFlag(MovementFlags(MOVEFLAG_FALLING | MOVEFLAG_FALLINGFAR))) GetPlayer()->m_movementInfo.HasMovementFlag(MovementFlags(MOVEFLAG_FALLING | MOVEFLAG_FALLINGFAR)))
{ {
@ -1082,12 +1081,16 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
recv_data >> guid; recv_data >> guid;
DEBUG_LOG("Inspected guid is %s", guid.GetString().c_str()); DEBUG_LOG("Inspected guid is %s", guid.GetString().c_str());
_player->SetSelectionGuid(guid);
Player* plr = sObjectMgr.GetPlayer(guid); Player* plr = sObjectMgr.GetPlayer(guid);
if (!plr) // wrong player if (!plr) // wrong player
return; return;
if (!_player->IsWithinDistInMap(plr, INSPECT_DISTANCE, false))
return;
if (_player->IsHostileTo(plr))
return;
WorldPacket data(SMSG_INSPECT_RESULTS, 50); WorldPacket data(SMSG_INSPECT_RESULTS, 50);
data << plr->GetObjectGuid(); data << plr->GetObjectGuid();
@ -1119,13 +1122,18 @@ void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data)
recv_data.ReadGuidBytes<4, 7, 0, 5, 1, 6, 2, 3>(guid); recv_data.ReadGuidBytes<4, 7, 0, 5, 1, 6, 2, 3>(guid);
Player* player = sObjectMgr.GetPlayer(guid); Player* player = sObjectMgr.GetPlayer(guid);
if (!player) if (!player)
{ {
sLog.outError("InspectHonorStats: WTF, player not found..."); sLog.outError("InspectHonorStats: WTF, player not found...");
return; return;
} }
if (!_player->IsWithinDistInMap(player, INSPECT_DISTANCE, false))
return;
if (_player->IsHostileTo(player))
return;
WorldPacket data(SMSG_INSPECT_HONOR_STATS, 18); WorldPacket data(SMSG_INSPECT_HONOR_STATS, 18);
data.WriteGuidMask<4, 3, 6, 2, 5, 0, 7, 1>(player->GetObjectGuid()); data.WriteGuidMask<4, 3, 6, 2, 5, 0, 7, 1>(player->GetObjectGuid());
data << uint8(0); // rank data << uint8(0); // rank
@ -1520,8 +1528,17 @@ void WorldSession::HandleQueryInspectAchievementsOpcode(WorldPacket& recv_data)
recv_data >> guid.ReadAsPacked(); recv_data >> guid.ReadAsPacked();
if (Player* player = sObjectMgr.GetPlayer(guid)) Player* player = sObjectMgr.GetPlayer(guid);
player->GetAchievementMgr().SendRespondInspectAchievements(_player); if (!player)
return;
if (!_player->IsWithinDistInMap(player, INSPECT_DISTANCE, false))
return;
if (_player->IsHostileTo(player))
return;
player->GetAchievementMgr().SendRespondInspectAchievements(_player);
} }
void WorldSession::HandleUITimeRequestOpcode(WorldPacket& /*recv_data*/) void WorldSession::HandleUITimeRequestOpcode(WorldPacket& /*recv_data*/)

View file

@ -477,6 +477,20 @@ void WorldSession::SendSpiritResurrect()
} }
} }
void WorldSession::HandleReturnToGraveyardOpcode(WorldPacket& recv_data)
{
Corpse* corpse = _player->GetCorpse();
if (!corpse)
return;
WorldSafeLocsEntry const* corpseGrave = sObjectMgr.GetClosestGraveYard(corpse->GetPositionX(), corpse->GetPositionY(),
corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam());
if (!corpseGrave)
return;
_player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
}
void WorldSession::HandleBinderActivateOpcode(WorldPacket& recv_data) void WorldSession::HandleBinderActivateOpcode(WorldPacket& recv_data)
{ {
ObjectGuid npcGuid; ObjectGuid npcGuid;

View file

@ -43,6 +43,10 @@ void WorldSession::HandleLearnTalentOpcode(WorldPacket& recv_data)
_player->SendTalentsInfoData(false); _player->SendTalentsInfoData(false);
else else
sLog.outError("WorldSession::HandleLearnTalentOpcode: learn talent %u rank %u failed for %s (account %u)", talent_id, requested_rank, GetPlayerName(), GetAccountId()); sLog.outError("WorldSession::HandleLearnTalentOpcode: learn talent %u rank %u failed for %s (account %u)", talent_id, requested_rank, GetPlayerName(), GetAccountId());
// if player has a pet, update owner talent auras
if (_player->GetPet())
_player->GetPet()->CastOwnerTalentAuras();
} }
void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket) void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
@ -84,6 +88,10 @@ void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
} }
_player->SendTalentsInfoData(false); _player->SendTalentsInfoData(false);
// if player has a pet, update owner talent auras
if (_player->GetPet())
_player->GetPet()->CastOwnerTalentAuras();
} }
void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recv_data) void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recv_data)
@ -99,9 +107,8 @@ void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recv_data)
return; return;
} }
// remove fake death if (!unit->CanTrainAndResetTalentsOf(_player))
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) return;
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if (!(_player->resetTalents())) if (!(_player->resetTalents()))
{ {
@ -114,6 +121,8 @@ void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recv_data)
_player->SendTalentsInfoData(false); _player->SendTalentsInfoData(false);
unit->CastSpell(_player, 14867, true); // spell: "Untalent Visual Effect" unit->CastSpell(_player, 14867, true); // spell: "Untalent Visual Effect"
if (_player->GetPet())
_player->GetPet()->CastOwnerTalentAuras();
} }
void WorldSession::HandleUnlearnSkillOpcode(WorldPacket& recv_data) void WorldSession::HandleUnlearnSkillOpcode(WorldPacket& recv_data)

View file

@ -519,10 +519,10 @@ void Spell::FillTargetMap()
// targets for TARGET_SCRIPT_COORDINATES (A) and TARGET_SCRIPT // targets for TARGET_SCRIPT_COORDINATES (A) and TARGET_SCRIPT
// for TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT (A) all is checked in Spell::CheckCast and in Spell::CheckItem // for TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT (A) all is checked in Spell::CheckCast and in Spell::CheckItem
// filled in Spell::CheckCast call // filled in Spell::CheckCast call
if(spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES || if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES ||
spellEffect->EffectImplicitTargetA == TARGET_SCRIPT || spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT ||
spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT || (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT && spellEffect->EffectImplicitTargetB != TARGET_SELF) ||
(spellEffect->EffectImplicitTargetB == TARGET_SCRIPT && spellEffect->EffectImplicitTargetA != TARGET_SELF)) (spellEffect->EffectImplicitTargetB == TARGET_SCRIPT && spellEffect->EffectImplicitTargetA != TARGET_SELF))
continue; continue;
// TODO: find a way so this is not needed? // TODO: find a way so this is not needed?
@ -571,8 +571,9 @@ void Spell::FillTargetMap()
case TARGET_SELF: case TARGET_SELF:
switch(spellEffect->EffectImplicitTargetB) switch(spellEffect->EffectImplicitTargetB)
{ {
case TARGET_NONE: case TARGET_NONE: // Fill Target based on A only
case TARGET_EFFECT_SELECT: case TARGET_EFFECT_SELECT:
case TARGET_SCRIPT: // B-target only used with CheckCast here
SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]);
break; break;
case TARGET_AREAEFFECT_INSTANT: // use B case that not dependent from from A in fact case TARGET_AREAEFFECT_INSTANT: // use B case that not dependent from from A in fact
@ -716,6 +717,17 @@ void Spell::FillTargetMap()
break; break;
} }
break; break;
case TARGET_SCRIPT:
switch (spellEffect->EffectImplicitTargetB)
{
case TARGET_SELF:
// Fill target based on B only, A is only used with CheckCast here.
SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]);
break;
default:
break;
}
break;
default: default:
switch(spellEffect->EffectImplicitTargetB) switch(spellEffect->EffectImplicitTargetB)
{ {
@ -3273,6 +3285,9 @@ void Spell::cast(bool skipCheck)
// Chaos Bane strength buff // Chaos Bane strength buff
else if (m_spellInfo->Id == 71904) else if (m_spellInfo->Id == 71904)
AddTriggeredSpell(73422); AddTriggeredSpell(73422);
// Weak Alcohol
else if (m_spellInfo->SpellIconID == 1306 && m_spellInfo->SpellVisual[0] == 11359)
AddTriggeredSpell(51655); // BOTM - Create Empty Brew Bottle
break; break;
} }
case SPELLFAMILY_MAGE: case SPELLFAMILY_MAGE:
@ -3710,14 +3725,20 @@ void Spell::update(uint32 difftime)
SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(EFFECT_INDEX_0); SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(EFFECT_INDEX_0);
SpellInterruptsEntry const* spellInterrupts = m_spellInfo->GetSpellInterrupts(); SpellInterruptsEntry const* spellInterrupts = m_spellInfo->GetSpellInterrupts();
// check if the player caster has moved before the spell finished if (m_CastItemGuid && !m_CastItem)
if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) && {
cancel();
return;
}
// check if the player or unit caster has moved before the spell finished (exclude casting on vehicles)
if (((m_caster->GetTypeId() == TYPEID_PLAYER || m_caster->GetTypeId() == TYPEID_UNIT) && m_timer != 0) &&
(m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) && (m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) &&
((spellEffect && spellEffect->Effect != SPELL_EFFECT_STUCK) || !((Player*)m_caster)->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLINGFAR)) && ((spellEffect && spellEffect->Effect != SPELL_EFFECT_STUCK) || !((Player*)m_caster)->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLINGFAR)) &&
!m_caster->HasAffectedAura(SPELL_AURA_ALLOW_CAST_WHILE_MOVING, m_spellInfo)) !m_caster->HasAffectedAura(SPELL_AURA_ALLOW_CAST_WHILE_MOVING, m_spellInfo))
{ {
// always cancel for channeled spells // always cancel for channeled spells
if (m_spellState == SPELL_STATE_CASTING) if (m_spellState == SPELL_STATE_CASTING && !m_spellInfo->HasAttribute(SPELL_ATTR_EX5_CAN_CHANNEL_WHEN_MOVING))
cancel(); cancel();
// don't cancel for melee, autorepeat, triggered and instant spells // don't cancel for melee, autorepeat, triggered and instant spells
else if(!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_IsTriggeredSpell && (spellInterrupts && spellInterrupts->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) else if(!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_IsTriggeredSpell && (spellInterrupts && spellInterrupts->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
@ -3743,16 +3764,20 @@ void Spell::update(uint32 difftime)
{ {
if (m_timer > 0) if (m_timer > 0)
{ {
if (m_caster->GetTypeId() == TYPEID_PLAYER) if (m_caster->GetTypeId() == TYPEID_PLAYER || m_caster->GetTypeId() == TYPEID_UNIT)
{ {
// check if player has jumped before the channeling finished // check if player has jumped before the channeling finished
if (((Player*)m_caster)->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLING) && if (m_caster->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLING) &&
!m_caster->HasAffectedAura(SPELL_AURA_ALLOW_CAST_WHILE_MOVING, m_spellInfo)) !m_caster->HasAffectedAura(SPELL_AURA_ALLOW_CAST_WHILE_MOVING, m_spellInfo))
cancel(); cancel();
// check for incapacitating player states // check for incapacitating player states
if (m_caster->hasUnitState(UNIT_STAT_CAN_NOT_REACT)) if (m_caster->hasUnitState(UNIT_STAT_CAN_NOT_REACT))
cancel(); {
// certain channel spells are not interrupted
if (!m_spellInfo->HasAttribute(SPELL_ATTR_EX_CHANNELED_1) && !m_spellInfo->HasAttribute(SPELL_ATTR_EX3_UNK28))
cancel();
}
// check if player has turned if flag is set // check if player has turned if flag is set
if( spellInterrupts && (spellInterrupts->ChannelInterruptFlags & CHANNEL_FLAG_TURNING) && m_castOrientation != m_caster->GetOrientation() ) if( spellInterrupts && (spellInterrupts->ChannelInterruptFlags & CHANNEL_FLAG_TURNING) && m_castOrientation != m_caster->GetOrientation() )
@ -3790,7 +3815,7 @@ void Spell::update(uint32 difftime)
continue; continue;
Unit* unit = m_caster->GetObjectGuid() == target.targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target.targetGUID); Unit* unit = m_caster->GetObjectGuid() == target.targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target.targetGUID);
if (unit == NULL) if (unit == nullptr)
continue; continue;
p->RewardPlayerAndGroupAtCast(unit, m_spellInfo->Id); p->RewardPlayerAndGroupAtCast(unit, m_spellInfo->Id);
@ -4082,7 +4107,7 @@ void Spell::SendSpellStart()
data << uint8(m_runesState); data << uint8(m_runesState);
data << uint8(caster->GetRunesState()); data << uint8(caster->GetRunesState());
for (uint8 i = 0; i < MAX_RUNES; ++i) for (uint8 i = 0; i < MAX_RUNES; ++i)
data << uint8(255 - ((caster->GetRuneCooldown(i) / REGEN_TIME_FULL) * 51)); data << uint8(caster->GetRuneCooldownFraction(i));
} }
else else
{ {
@ -4702,6 +4727,7 @@ void Spell::TakePower()
if (m_spellInfo->powerType == POWER_HEALTH) if (m_spellInfo->powerType == POWER_HEALTH)
{ {
m_caster->ModifyHealth(-(int32)m_powerCost); m_caster->ModifyHealth(-(int32)m_powerCost);
m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, m_powerCost, GetSpellSchoolMask(m_spellInfo), 0, 0, false, 0, false);
return; return;
} }
@ -4740,14 +4766,14 @@ void Spell::TakePower()
if (powerType == POWER_RUNE) if (powerType == POWER_RUNE)
{ {
CheckOrTakeRunePower(hit); TakeRunePower(hit);
return; return;
} }
m_caster->ModifyPower(powerType, -(int32)m_powerCost); m_caster->ModifyPower(powerType, -(int32)m_powerCost);
} }
SpellCastResult Spell::CheckOrTakeRunePower(bool take) SpellCastResult Spell::CheckRunePower()
{ {
if (m_caster->GetTypeId() != TYPEID_PLAYER) if (m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_CAST_OK; return SPELL_CAST_OK;
@ -4758,83 +4784,127 @@ SpellCastResult Spell::CheckOrTakeRunePower(bool take)
return SPELL_CAST_OK; return SPELL_CAST_OK;
SpellRuneCostEntry const* src = sSpellRuneCostStore.LookupEntry(m_spellInfo->runeCostID); SpellRuneCostEntry const* src = sSpellRuneCostStore.LookupEntry(m_spellInfo->runeCostID);
if (!src || (src->NoRuneCost() && (!take || src->NoRunicPowerGain())))
if (!src)
return SPELL_CAST_OK; return SPELL_CAST_OK;
m_runesState = plr->GetRunesState(); // store previous state if (src->NoRuneCost())
return SPELL_CAST_OK;
int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death // at this moment for rune cost exist only no cost mods, and no percent mods
int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death
// init cost data and apply mods for (uint32 i = 0; i < RUNE_DEATH; ++i)
for (uint8 i = 0; i < RUNE_DEATH; ++i)
{ {
runeCost[i] = src->RuneCost[i]; runeCost[i] = src->RuneCost[i];
if (Player* modOwner = plr->GetSpellModOwner()) if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this); modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i]);
} }
runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
// scan non-death runes (death rune not used explicitly in rune costs) for (uint32 i = 0; i < MAX_RUNES; ++i)
for (uint8 i = 0; i < MAX_RUNES; ++i)
{ {
// already used
if (plr->GetRuneCooldown(i) != 0)
continue;
RuneType rune = plr->GetCurrentRune(i); RuneType rune = plr->GetCurrentRune(i);
if (plr->GetRuneCooldown(i) == 0 && runeCost[rune] > 0) if (!plr->GetRuneCooldown(i) && runeCost[rune] > 0)
--runeCost[rune];
}
for (uint32 i = 0; i < RUNE_DEATH; ++i)
if (runeCost[i] > 0)
runeCost[RUNE_DEATH] += runeCost[i];
if (runeCost[RUNE_DEATH] > MAX_RUNES)
return SPELL_FAILED_NO_POWER; // not sure if result code is correct
return SPELL_CAST_OK;
}
void Spell::TakeRunePower(bool hit)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* plr = (Player*)m_caster;
if (plr->getClass() != CLASS_DEATH_KNIGHT)
return;
SpellRuneCostEntry const* src = sSpellRuneCostStore.LookupEntry(m_spellInfo->runeCostID);
if (!src)
return;
if (src->NoRuneCost() && src->NoRunicPowerGain())
return;
m_runesState = plr->GetRunesState(); // store previous state
// at this moment for rune cost exist only no cost mods, and no percent mods
int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death
for (uint32 i = 0; i < RUNE_DEATH; ++i)
{
runeCost[i] = src->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i]);
}
runeCost[RUNE_DEATH] = 0; // calculated later
plr->ClearLastUsedRuneMask();
for (uint32 i = 0; i < MAX_RUNES; ++i)
{
RuneType rune = plr->GetCurrentRune(i);
if (!plr->GetRuneCooldown(i) && runeCost[rune] > 0)
{ {
RuneType rune = plr->GetCurrentRune(i); uint16 baseCd = hit ? uint16(RUNE_BASE_COOLDOWN) : uint16(RUNE_MISS_COOLDOWN);
if (runeCost[rune] <= 0) plr->SetBaseRuneCooldown(i, baseCd);
continue; plr->SetRuneCooldown(i, baseCd);
plr->SetLastUsedRune(rune);
// already used
if (plr->GetRuneCooldown(i) != 0)
continue;
if (take)
plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec
--runeCost[rune]; --runeCost[rune];
} }
} }
// collect all not counted rune costs to death runes cost runeCost[RUNE_DEATH] = runeCost[RUNE_BLOOD] + runeCost[RUNE_UNHOLY] + runeCost[RUNE_FROST];
for (uint8 i = 0; i < RUNE_DEATH; ++i)
if (runeCost[i] > 0)
runeCost[RUNE_DEATH] += runeCost[i];
// scan death runes
if (runeCost[RUNE_DEATH] > 0) if (runeCost[RUNE_DEATH] > 0)
{ {
for (uint8 i = 0; i < MAX_RUNES; ++i) for (uint32 i = 0; i < MAX_RUNES; ++i)
{ {
RuneType rune = plr->GetCurrentRune(i); RuneType rune = plr->GetCurrentRune(i);
if (!plr->GetRuneCooldown(i) && rune == RUNE_DEATH) if (!plr->GetRuneCooldown(i) && rune == RUNE_DEATH)
{ {
plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec uint16 baseCd = hit ? uint16(RUNE_BASE_COOLDOWN) : uint16(RUNE_MISS_COOLDOWN);
runeCost[rune]--; plr->SetBaseRuneCooldown(i, baseCd);
plr->SetRuneCooldown(i, baseCd);
plr->SetLastUsedRune(rune);
--runeCost[rune];
if (take) // keep Death Rune type if missed
plr->ConvertRune(i, plr->GetBaseRune(i)); if (hit)
plr->RestoreBaseRune(i);
if (runeCost[RUNE_DEATH] == 0) if (runeCost[RUNE_DEATH] == 0)
return SPELL_FAILED_NO_POWER; break;
} }
} }
} }
if (take) if (hit)
{ {
// you can gain some runic power when use runes // you can gain some runic power when use runes
float rp = float(src->runePowerGain); int32 rp = int32(src->runePowerGain);
rp *= sWorld.getConfig(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_INCOME); if (rp)
plr->ModifyPower(POWER_RUNIC_POWER, (int32)rp); {
} if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, rp);
return SPELL_CAST_OK; rp = int32(sWorld.getConfig(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_INCOME) * rp);
rp += m_caster->GetTotalAuraModifier(SPELL_AURA_MOD_RUNIC_POWER_REGEN) * rp / 100;
if (rp > 0)
plr->ModifyPower(POWER_RUNIC_POWER, (int32)rp);
}
}
} }
void Spell::TakeReagents() void Spell::TakeReagents()
@ -5437,12 +5507,12 @@ SpellCastResult Spell::CheckCast(bool strict)
continue; continue;
if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT || if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT ||
(spellEffect->EffectImplicitTargetB == TARGET_SCRIPT && spellEffect->EffectImplicitTargetA != TARGET_SELF) || spellEffect->EffectImplicitTargetB == TARGET_SCRIPT ||
spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES || spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES ||
spellEffect->EffectImplicitTargetB == TARGET_SCRIPT_COORDINATES || spellEffect->EffectImplicitTargetB == TARGET_SCRIPT_COORDINATES ||
spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT ||
spellEffect->EffectImplicitTargetB == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT)
{ {
SQLMultiStorage::SQLMSIteratorBounds<SpellTargetEntry> bounds = sSpellScriptTargetStorage.getBounds<SpellTargetEntry>(m_spellInfo->Id); SQLMultiStorage::SQLMSIteratorBounds<SpellTargetEntry> bounds = sSpellScriptTargetStorage.getBounds<SpellTargetEntry>(m_spellInfo->Id);
if (bounds.first == bounds.second) if (bounds.first == bounds.second)
@ -5453,13 +5523,17 @@ SpellCastResult Spell::CheckCast(bool strict)
if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES || spellEffect->EffectImplicitTargetB == TARGET_SCRIPT_COORDINATES) if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES || spellEffect->EffectImplicitTargetB == TARGET_SCRIPT_COORDINATES)
sLog.outErrorDb("Spell entry %u, effect %i has EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT_COORDINATES, but gameobject or creature are not defined in `spell_script_target`", m_spellInfo->Id, j); sLog.outErrorDb("Spell entry %u, effect %i has EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT_COORDINATES, but gameobject or creature are not defined in `spell_script_target`", m_spellInfo->Id, j);
if (spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) if (spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT || spellEffect->EffectImplicitTargetB == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT)
sLog.outErrorDb("Spell entry %u, effect %i has EffectImplicitTargetA/EffectImplicitTargetB = TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT, but gameobject are not defined in `spell_script_target`", m_spellInfo->Id, j); sLog.outErrorDb("Spell entry %u, effect %i has EffectImplicitTargetA/EffectImplicitTargetB = TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT, but gameobject are not defined in `spell_script_target`", m_spellInfo->Id, j);
} }
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
float range = GetSpellMaxRange(srange); float range = GetSpellMaxRange(srange);
// override range with default when it's not provided
if (!range)
range = m_caster->GetMap()->IsDungeon() ? DEFAULT_VISIBILITY_INSTANCE : DEFAULT_VISIBILITY_DISTANCE;
Creature* targetExplicit = NULL; // used for cases where a target is provided (by script for example) Creature* targetExplicit = NULL; // used for cases where a target is provided (by script for example)
Creature* creatureScriptTarget = NULL; Creature* creatureScriptTarget = NULL;
GameObject* goScriptTarget = NULL; GameObject* goScriptTarget = NULL;
@ -5905,12 +5979,6 @@ SpellCastResult Spell::CheckCast(bool strict)
if (ReqValue > skillValue) if (ReqValue > skillValue)
return SPELL_FAILED_LOW_CASTLEVEL; return SPELL_FAILED_LOW_CASTLEVEL;
// chance for fail at orange skinning attempt
if ((m_selfContainer && (*m_selfContainer) == this) &&
skillValue < sWorld.GetConfigMaxSkillValue() &&
(ReqValue < 0 ? 0 : ReqValue) > irand(skillValue - 25, skillValue + 37))
return SPELL_FAILED_TRY_AGAIN;
break; break;
} }
case SPELL_EFFECT_OPEN_LOCK: case SPELL_EFFECT_OPEN_LOCK:
@ -5962,9 +6030,10 @@ SpellCastResult Spell::CheckCast(bool strict)
if (res != SPELL_CAST_OK) if (res != SPELL_CAST_OK)
return res; return res;
// chance for fail at orange mining/herb/LockPicking gathering attempt // Failing gathering attempt for mining and herbalism was removed in patch 3.1.0: http://wowwiki.wikia.com/wiki/Patch_3.1.0
// chance for fail at orange LockPicking gathering attempt
// second check prevent fail at rechecks // second check prevent fail at rechecks
if (skillId != SKILL_NONE && (!m_selfContainer || ((*m_selfContainer) != this))) if (m_spellState != SPELL_STATE_CREATED && skillId != SKILL_NONE && skillId != SKILL_HERBALISM && skillId != SKILL_MINING )
{ {
bool canFailAtMax = skillId != SKILL_HERBALISM && skillId != SKILL_MINING; bool canFailAtMax = skillId != SKILL_HERBALISM && skillId != SKILL_MINING;
@ -5972,7 +6041,6 @@ SpellCastResult Spell::CheckCast(bool strict)
if ((canFailAtMax || skillValue < sWorld.GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue - 25, skillValue + 37)) if ((canFailAtMax || skillValue < sWorld.GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue - 25, skillValue + 37))
return SPELL_FAILED_TRY_AGAIN; return SPELL_FAILED_TRY_AGAIN;
} }
break;
} }
case SPELL_EFFECT_SUMMON_DEAD_PET: case SPELL_EFFECT_SUMMON_DEAD_PET:
{ {
@ -6823,7 +6891,7 @@ SpellCastResult Spell::CheckPower()
// check rune cost only if a spell has PowerType == POWER_RUNE // check rune cost only if a spell has PowerType == POWER_RUNE
if (m_spellInfo->powerType == POWER_RUNE) if (m_spellInfo->powerType == POWER_RUNE)
{ {
SpellCastResult failReason = CheckOrTakeRunePower(false); SpellCastResult failReason = CheckRunePower();
if (failReason != SPELL_CAST_OK) if (failReason != SPELL_CAST_OK)
return failReason; return failReason;
} }

View file

@ -235,10 +235,12 @@ inline ByteBuffer& operator>> (ByteBuffer& buf, SpellCastTargetsReader const& ta
enum SpellState enum SpellState
{ {
SPELL_STATE_PREPARING = 0, // cast time delay period, non channeled spell SPELL_STATE_CREATED = 0, // just created
SPELL_STATE_CASTING = 1, // channeled time period spell casting state SPELL_STATE_STARTING = 1, // doing initial check
SPELL_STATE_FINISHED = 2, // cast finished to success or fail SPELL_STATE_PREPARING = 2, // cast time delay period, non channeled spell
SPELL_STATE_DELAYED = 3 // spell casted but need time to hit target(s) SPELL_STATE_CASTING = 3, // channeled time period spell casting state
SPELL_STATE_FINISHED = 4, // cast finished to success or fail
SPELL_STATE_DELAYED = 5 // spell casted but need time to hit target(s)
}; };
enum SpellTargets enum SpellTargets
@ -396,6 +398,7 @@ class Spell
void cast(bool skipCheck = false); void cast(bool skipCheck = false);
void finish(bool ok = true); void finish(bool ok = true);
void TakePower(); void TakePower();
void TakeRunePower(bool hit);
void TakeAmmo(); void TakeAmmo();
void TakeReagents(); void TakeReagents();
void TakeCastItem(); void TakeCastItem();
@ -413,7 +416,7 @@ class Spell
SpellCastResult CheckItems(); SpellCastResult CheckItems();
SpellCastResult CheckRange(bool strict); SpellCastResult CheckRange(bool strict);
SpellCastResult CheckPower(); SpellCastResult CheckPower();
SpellCastResult CheckOrTakeRunePower(bool take); SpellCastResult CheckRunePower();
SpellCastResult CheckCasterAuras() const; SpellCastResult CheckCasterAuras() const;
int32 CalculateDamage(SpellEffectIndex i, Unit* target) { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_currentBasePoints[i]); } int32 CalculateDamage(SpellEffectIndex i, Unit* target) { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_currentBasePoints[i]); }
@ -455,6 +458,8 @@ class Spell
SpellEntry const* m_triggeredBySpellInfo; SpellEntry const* m_triggeredBySpellInfo;
SpellInterruptsEntry const* m_spellInterrupts; SpellInterruptsEntry const* m_spellInterrupts;
int32 m_currentBasePoints[MAX_EFFECT_INDEX]; // cache SpellEntry::CalculateSimpleValue and use for set custom base points int32 m_currentBasePoints[MAX_EFFECT_INDEX]; // cache SpellEntry::CalculateSimpleValue and use for set custom base points
ObjectGuid m_CastItemGuid;
Item* m_CastItem; Item* m_CastItem;
uint8 m_cast_count; uint8 m_cast_count;
uint32 m_glyphIndex; uint32 m_glyphIndex;

View file

@ -363,7 +363,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS] =
&Aura::HandleNULL, //297 14 spells in 4.3.4 &Aura::HandleNULL, //297 14 spells in 4.3.4
&Aura::HandleUnused, //298 6 spells in 4.3.4 &Aura::HandleUnused, //298 6 spells in 4.3.4
&Aura::HandleUnused, //299 unused (3.2.2a-4.3.4) &Aura::HandleUnused, //299 unused (3.2.2a-4.3.4)
&Aura::HandleNULL, //300 21 spells (share damage?) &Aura::HandleNoImmediateEffect, //300 SPELL_AURA_SHARE_DAMAGE_PCT 21 spells
&Aura::HandleNULL, //301 SPELL_AURA_HEAL_ABSORB 31 spells &Aura::HandleNULL, //301 SPELL_AURA_HEAL_ABSORB 31 spells
&Aura::HandleUnused, //302 unused (3.2.2a-4.3.4) &Aura::HandleUnused, //302 unused (3.2.2a-4.3.4)
&Aura::HandleNULL, //303 35 spells increases damage done vs. creature type &Aura::HandleNULL, //303 35 spells increases damage done vs. creature type
@ -510,7 +510,8 @@ Aura::~Aura()
} }
AreaAura::AreaAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* currentBasePoints, SpellAuraHolder* holder, Unit* target, AreaAura::AreaAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* currentBasePoints, SpellAuraHolder* holder, Unit* target,
Unit* caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem) Unit* caster, Item* castItem, uint32 originalRankSpellId)
: Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem), m_originalRankSpellId(originalRankSpellId)
{ {
m_isAreaAura = true; m_isAreaAura = true;
@ -751,18 +752,26 @@ void AreaAura::Update(uint32 diff)
// flag for selection is need apply aura to current iteration target // flag for selection is need apply aura to current iteration target
bool apply = true; bool apply = true;
SpellEntry const* actualSpellInfo;
if (GetCasterGuid() == (*tIter)->GetObjectGuid()) // if caster is same as target then no need to change rank of the spell
actualSpellInfo = GetSpellProto();
else
actualSpellInfo = sSpellMgr.SelectAuraRankForLevel(GetSpellProto(), (*tIter)->getLevel()); // use spell id according level of the target
if (!actualSpellInfo)
continue;
Unit::SpellAuraHolderBounds spair = (*tIter)->GetSpellAuraHolderBounds(actualSpellInfo->Id);
// we need ignore present caster self applied are auras sometime // we need ignore present caster self applied are auras sometime
// in cases if this only auras applied for spell effect // in cases if this only auras applied for spell effect
Unit::SpellAuraHolderBounds spair = (*tIter)->GetSpellAuraHolderBounds(GetId());
for (Unit::SpellAuraHolderMap::const_iterator i = spair.first; i != spair.second; ++i) for (Unit::SpellAuraHolderMap::const_iterator i = spair.first; i != spair.second; ++i)
{ {
if (i->second->IsDeleted()) if (i->second->IsDeleted())
{ continue; } continue;
Aura* aur = i->second->GetAuraByEffectIndex(m_effIndex); Aura* aur = i->second->GetAuraByEffectIndex(m_effIndex);
if (!aur) if (!aur)
{ continue; } continue;
switch (m_areaAuraType) switch (m_areaAuraType)
{ {
@ -773,7 +782,7 @@ void AreaAura::Update(uint32 diff)
break; break;
case AREA_AURA_RAID: case AREA_AURA_RAID:
// non caster self-casted auras (stacked from diff. casters) // non caster self-casted auras (stacked from diff. casters)
if (aur->GetModifier()->m_auraname != SPELL_AURA_NONE || i->second->GetCasterGuid() == GetCasterGuid()) if (aur->GetModifier()->m_auraname != SPELL_AURA_NONE || i->second->GetCasterGuid() == GetCasterGuid())
apply = false; apply = false;
break; break;
default: default:
@ -787,43 +796,41 @@ void AreaAura::Update(uint32 diff)
} }
if (!apply) if (!apply)
{ continue; } continue;
// Skip some targets (TODO: Might require better checks, also unclear how the actual caster must/can be handled) // Skip some targets (TODO: Might require better checks, also unclear how the actual caster must/can be handled)
if (GetSpellProto()->HasAttribute(SPELL_ATTR_EX3_TARGET_ONLY_PLAYER) && (*tIter)->GetTypeId() != TYPEID_PLAYER) if (actualSpellInfo->HasAttribute(SPELL_ATTR_EX3_TARGET_ONLY_PLAYER) && (*tIter)->GetTypeId() != TYPEID_PLAYER)
{ continue; } continue;
if (SpellEntry const* actualSpellInfo = sSpellMgr.SelectAuraRankForLevel(GetSpellProto(), (*tIter)->getLevel())) int32 actualBasePoints = m_currentBasePoints;
// recalculate basepoints for lower rank (all AreaAura spell not use custom basepoints?)
if (actualSpellInfo != GetSpellProto())
actualBasePoints = actualSpellInfo->CalculateSimpleValue(m_effIndex);
SpellAuraHolder* holder = (*tIter)->GetSpellAuraHolder(actualSpellInfo->Id, GetCasterGuid());
bool addedToExisting = true;
if (!holder)
{ {
int32 actualBasePoints = m_currentBasePoints; holder = CreateSpellAuraHolder(actualSpellInfo, (*tIter), caster);
// recalculate basepoints for lower rank (all AreaAura spell not use custom basepoints?) addedToExisting = false;
if (actualSpellInfo != GetSpellProto())
{ actualBasePoints = actualSpellInfo->CalculateSimpleValue(m_effIndex); }
SpellAuraHolder* holder = (*tIter)->GetSpellAuraHolder(actualSpellInfo->Id, GetCasterGuid());
bool addedToExisting = true;
if (!holder)
{
holder = CreateSpellAuraHolder(actualSpellInfo, (*tIter), caster);
addedToExisting = false;
}
holder->SetAuraDuration(GetAuraDuration());
AreaAura* aur = new AreaAura(actualSpellInfo, m_effIndex, &actualBasePoints, holder, (*tIter), caster, NULL);
holder->AddAura(aur, m_effIndex);
if (addedToExisting)
{
(*tIter)->AddAuraToModList(aur);
holder->SetInUse(true);
aur->ApplyModifier(true, true);
holder->SetInUse(false);
}
else
(*tIter)->AddSpellAuraHolder(holder);
} }
holder->SetAuraDuration(GetAuraDuration());
AreaAura* aur = new AreaAura(actualSpellInfo, m_effIndex, &actualBasePoints, holder, (*tIter), caster, nullptr, GetSpellProto()->Id);
holder->AddAura(aur, m_effIndex);
if (addedToExisting)
{
(*tIter)->AddAuraToModList(aur);
holder->SetInUse(true);
aur->ApplyModifier(true, true);
holder->SetInUse(false);
}
else
(*tIter)->AddSpellAuraHolder(holder);
} }
} }
Aura::Update(diff); Aura::Update(diff);
@ -832,6 +839,7 @@ void AreaAura::Update(uint32 diff)
{ {
Unit* caster = GetCaster(); Unit* caster = GetCaster();
Unit* target = GetTarget(); Unit* target = GetTarget();
uint32 originalRankSpellId = m_originalRankSpellId ? m_originalRankSpellId : GetId(); // caster may have different spell id if target has lower level
Aura::Update(diff); Aura::Update(diff);
@ -839,9 +847,10 @@ void AreaAura::Update(uint32 diff)
// or caster is isolated or caster no longer has the aura // or caster is isolated or caster no longer has the aura
// or caster is (no longer) friendly // or caster is (no longer) friendly
bool needFriendly = (m_areaAuraType == AREA_AURA_ENEMY ? false : true); bool needFriendly = (m_areaAuraType == AREA_AURA_ENEMY ? false : true);
if (!caster || caster->hasUnitState(UNIT_STAT_ISOLATED) || if (!caster ||
!caster->IsWithinDistInMap(target, m_radius) || caster->hasUnitState(UNIT_STAT_ISOLATED) ||
!caster->HasAura(GetId(), GetEffIndex()) || !caster->HasAura(originalRankSpellId, GetEffIndex()) ||
!caster->IsWithinDistInMap(target, m_radius) ||
caster->IsFriendlyTo(target) != needFriendly caster->IsFriendlyTo(target) != needFriendly
) )
{ {
@ -854,29 +863,29 @@ void AreaAura::Update(uint32 diff)
{ {
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself(); Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
Group* pGroup = check ? check->GetGroup() : NULL; Group* pGroup = check ? check->GetGroup() : nullptr;
if (pGroup) if (pGroup)
{ {
Player* checkTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself(); Player* checkTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!checkTarget || !pGroup->SameSubGroup(check, checkTarget)) if (!checkTarget || !pGroup->SameSubGroup(check, checkTarget))
{ target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid()); } target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
} }
else else
{ target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid()); } target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
} }
} }
else if (m_areaAuraType == AREA_AURA_RAID) // TODO: fix me! else if (m_areaAuraType == AREA_AURA_RAID) // Check if on same raid group
{ {
// not check group if target == owner or target == pet // not check group if target == owner or target == pet
if (caster->GetCharmerOrOwnerGuid() != target->GetObjectGuid() && caster->GetObjectGuid() != target->GetCharmerOrOwnerGuid()) if (caster->GetCharmerOrOwnerGuid() != target->GetObjectGuid() && caster->GetObjectGuid() != target->GetCharmerOrOwnerGuid())
{ {
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself(); Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
Group* pGroup = check ? check->GetGroup() : NULL; Group* pGroup = check ? check->GetGroup() : nullptr;
if (pGroup) if (pGroup)
{ {
Player* checkTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself(); Player* checkTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!checkTarget) if (!checkTarget || !checkTarget->GetGroup() || checkTarget->GetGroup()->GetId() != pGroup->GetId())
target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid()); target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
} }
else else
@ -886,7 +895,7 @@ void AreaAura::Update(uint32 diff)
else if (m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER) else if (m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER)
{ {
if (target->GetObjectGuid() != caster->GetCharmerOrOwnerGuid()) if (target->GetObjectGuid() != caster->GetCharmerOrOwnerGuid())
{ target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid()); } target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
} }
} }
} }
@ -1191,7 +1200,7 @@ void Aura::TriggerSpell()
{ {
int32 damageForTick[8] = { 500, 500, 1000, 1000, 2000, 2000, 3000, 5000 }; int32 damageForTick[8] = { 500, 500, 1000, 1000, 2000, 2000, 3000, 5000 };
triggerTarget->CastCustomSpell(triggerTarget, 19698, &damageForTick[GetAuraTicks() - 1], nullptr, nullptr, true, nullptr); triggerTarget->CastCustomSpell(triggerTarget, 19698, &damageForTick[GetAuraTicks() - 1], nullptr, nullptr, true, nullptr);
return; return;;
} }
// // Frostwolf Muzzle DND // // Frostwolf Muzzle DND
@ -3526,62 +3535,18 @@ void Aura::HandleAuraFeatherFall(bool apply, bool Real)
{ {
// only at real add/remove aura // only at real add/remove aura
if (!Real) if (!Real)
{ return; } return;
Unit* target = GetTarget();
WorldPacket data;
target->BuildMoveFeatherFallPacket(&data, apply, 0);
target->SendMessageToSet(&data, true);
// start fall from current height GetTarget()->SetFeatherFall(apply);
if (!apply && target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->SetFallInformation(0, target->GetPositionZ());
} }
void Aura::HandleAuraHover(bool apply, bool Real) void Aura::HandleAuraHover(bool apply, bool Real)
{ {
// only at real add/remove aura // only at real add/remove aura
if (!Real) if (!Real)
{ return; } return;
WorldPacket data; GetTarget()->SetHover(apply);
if (apply)
{
GetTarget()->m_movementInfo.AddMovementFlag(MOVEFLAG_HOVER);
if (GetTarget()->GetTypeId() == TYPEID_PLAYER)
{
data.Initialize(SMSG_MOVE_SET_HOVER, 8 + 4 + 1);
data.WriteGuidMask<1, 4, 2, 3, 0, 5, 6, 7>(GetTarget()->GetObjectGuid());
data.WriteGuidBytes<5, 4, 1, 2, 3, 6, 0, 7>(GetTarget()->GetObjectGuid());
data << uint32(0);
}
else
{
data.Initialize(SMSG_SPLINE_MOVE_SET_HOVER, 8 + 4 + 1);
data.WriteGuidMask<3, 7, 0, 1, 4, 6, 2, 5>(GetTarget()->GetObjectGuid());
data.WriteGuidBytes<2, 4, 3, 1, 7, 0, 5, 6>(GetTarget()->GetObjectGuid());
GetTarget()->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM);
}
}
else
{
GetTarget()->m_movementInfo.RemoveMovementFlag(MOVEFLAG_HOVER);
data.Initialize(GetTarget()->GetTypeId() == TYPEID_PLAYER ? SMSG_MOVE_UNSET_HOVER : SMSG_SPLINE_MOVE_UNSET_HOVER, 8+4);
if (GetTarget()->GetTypeId() == TYPEID_PLAYER)
{
data.Initialize(SMSG_MOVE_UNSET_HOVER, 8 + 4 + 1);
data.WriteGuidMask<4, 6, 3, 1, 2, 7, 5, 0>(GetTarget()->GetObjectGuid());
data.WriteGuidBytes<4, 5, 3, 6, 7, 1, 2, 0>(GetTarget()->GetObjectGuid());
data << uint32(0);
}
else
{
data.Initialize(SMSG_SPLINE_MOVE_UNSET_HOVER, 8 + 4 + 1);
data.WriteGuidMask<6, 7, 4, 0, 3, 1, 5, 2>(GetTarget()->GetObjectGuid());
data.WriteGuidBytes<4, 5, 3, 0, 2, 7, 6, 1>(GetTarget()->GetObjectGuid());
GetTarget()->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM);
}
}
GetTarget()->SendMessageToSet(&data, true);
} }
void Aura::HandleWaterBreathing(bool /*apply*/, bool /*Real*/) void Aura::HandleWaterBreathing(bool /*apply*/, bool /*Real*/)
@ -4069,8 +4034,7 @@ void Aura::HandleAuraTransform(bool apply, bool Real)
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
if (caster->HasAura(52648)) // Glyph of the Penguin if (caster->HasAura(52648)) // Glyph of the Penguin
model_id = 26452; model_id = 26452;
else else if (caster->HasAura(57927)) // Glyph of the Monkey
if (caster->HasAura(57927)) // Glyph of the Monkey
model_id = 21362; model_id = 21362;
target->SetDisplayId(model_id); target->SetDisplayId(model_id);
@ -5209,9 +5173,7 @@ void Aura::HandleAuraModIncreaseFlightSpeed(bool apply, bool Real)
// Enable Fly mode for flying mounts // Enable Fly mode for flying mounts
if (m_modifier.m_auraname == SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED) if (m_modifier.m_auraname == SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED)
{ {
WorldPacket data; target->SetCanFly(apply);
target->BuildMoveSetCanFlyPacket(&data, apply, 0);
target->SendMessageToSet(&data, true);
// Players on flying mounts must be immune to polymorph // Players on flying mounts must be immune to polymorph
if (target->GetTypeId() == TYPEID_PLAYER) if (target->GetTypeId() == TYPEID_PLAYER)
@ -7109,10 +7071,7 @@ void Aura::HandleAuraAllowFlight(bool apply, bool Real)
if (!Real) if (!Real)
return; return;
// allow fly GetTarget()->SetCanFly(apply);
WorldPacket data;
GetTarget()->BuildMoveSetCanFlyPacket(&data, apply, 0);
GetTarget()->SendMessageToSet(&data, true);
} }
void Aura::HandleModRating(bool apply, bool Real) void Aura::HandleModRating(bool apply, bool Real)

View file

@ -545,13 +545,14 @@ class Aura
class AreaAura : public Aura class AreaAura : public Aura
{ {
public: public:
AreaAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* currentBasePoints, SpellAuraHolder* holder, Unit* target, Unit* caster = NULL, Item* castItem = NULL); AreaAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* currentBasePoints, SpellAuraHolder* holder, Unit* target, Unit* caster = nullptr, Item* castItem = nullptr, uint32 originalRankSpellId = 0);
~AreaAura(); ~AreaAura();
protected: protected:
void Update(uint32 diff) override; void Update(uint32 diff) override;
private: private:
float m_radius; float m_radius;
AreaAuraType m_areaAuraType; AreaAuraType m_areaAuraType;
uint32 m_originalRankSpellId;
}; };
class PersistentAreaAura : public Aura class PersistentAreaAura : public Aura

View file

@ -222,7 +222,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS] =
&Spell::EffectQuestOffer, //150 SPELL_EFFECT_QUEST_OFFER &Spell::EffectQuestOffer, //150 SPELL_EFFECT_QUEST_OFFER
&Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
&Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
&Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry &Spell::EffectCreateTamedPet, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
&Spell::EffectTeachTaxiNode, //154 SPELL_EFFECT_TEACH_TAXI_NODE single spell: Teach River's Heart Taxi Path &Spell::EffectTeachTaxiNode, //154 SPELL_EFFECT_TEACH_TAXI_NODE single spell: Teach River's Heart Taxi Path
&Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal. &Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
&Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
@ -4191,17 +4191,12 @@ void Spell::EffectTriggerSpell(SpellEffectEntry const* effect)
pet->CastSpell(pet, 28305, true); pet->CastSpell(pet, 28305, true);
return; return;
} }
case 53258: // Empower Rune Weapon case 58832: // Mirror Image
{ {
// remove cooldown of frost/death, undead/blood activated in main spell // Glyph of Mirror Image
if (unitTarget->GetTypeId() == TYPEID_PLAYER) if (m_caster->HasAura(63093))
{ m_caster->CastSpell(m_caster, 65047, true, m_CastItem, nullptr, m_originalCasterGUID);
bool res1 = ((Player*)unitTarget)->ActivateRunes(RUNE_FROST, 2); break;
bool res2 = ((Player*)unitTarget)->ActivateRunes(RUNE_DEATH, 2);
if (res1 || res2)
((Player*)unitTarget)->ResyncRunes();
}
return;
} }
} }
@ -4339,7 +4334,11 @@ void Spell::EffectJump(SpellEffectEntry const* effect)
return; return;
} }
m_caster->NearTeleportTo(x, y, z, o, true); // TODO Implement this as jump movement? // Try to normalize Z coord because GetContactPoint do nothing with Z axis
m_caster->UpdateAllowedPositionZ(x, y, z);
float speed = m_spellInfo->speed ? m_spellInfo->speed : 27.0f;
m_caster->GetMotionMaster()->MoveDestination(x, y, z, o, speed, 2.5f);
} }
void Spell::EffectTeleportUnits(SpellEffectEntry const* effect) // TODO - Use target settings for this effect! void Spell::EffectTeleportUnits(SpellEffectEntry const* effect) // TODO - Use target settings for this effect!
@ -6629,56 +6628,45 @@ void Spell::EffectSummonPet(SpellEffectEntry const* effect)
{ {
uint32 petentry = effect->EffectMiscValue; uint32 petentry = effect->EffectMiscValue;
Pet* OldSummon = m_caster->GetPet();
// if pet requested type already exist
if (OldSummon)
{
if ((petentry == 0 || OldSummon->GetEntry() == petentry) && OldSummon->getPetType() != SUMMON_PET)
{
// pet in corpse state can't be summoned
if (OldSummon->IsDead())
return;
OldSummon->GetMap()->Remove((Creature*)OldSummon, false);
float px, py, pz;
m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectBoundingRadius());
OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
m_caster->GetMap()->Add((Creature*)OldSummon);
if (m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled())
{
((Player*)m_caster)->PetSpellInitialize();
}
return;
}
if (m_caster->GetTypeId() == TYPEID_PLAYER)
OldSummon->Unsummon(OldSummon->getPetType() == HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT, m_caster);
else
return;
}
CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(petentry);
// == 0 in case call current pet, check only real summon case
if (petentry && !cInfo)
{
sLog.outErrorDb("EffectSummonPet: creature entry %u not found for spell %u.", petentry, m_spellInfo->Id);
return;
}
Pet* NewSummon = new Pet; Pet* NewSummon = new Pet;
// petentry==0 for hunter "call pet" (current pet summoned if any) if (m_caster->GetTypeId() == TYPEID_PLAYER)
if (m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster, petentry))
return;
// not error in case fail hunter call pet
if (!petentry)
{ {
switch(m_caster->getClass())
{
case CLASS_HUNTER:
{
// Everything already taken care of, we are only here because we loaded pet from db successfully
delete NewSummon;
return;
}
default:
{
if (Pet* OldSummon = m_caster->GetPet())
OldSummon->Unsummon(PET_SAVE_NOT_IN_SLOT, m_caster);
// Load pet from db; if any to load
if (NewSummon->LoadPetFromDB((Player*)m_caster, petentry))
{
NewSummon->SetHealth(NewSummon->GetMaxHealth());
NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
return;
}
NewSummon->setPetType(SUMMON_PET);
}
}
}
else
NewSummon->setPetType(GUARDIAN_PET);
CreatureInfo const* cInfo = petentry ? ObjectMgr::GetCreatureTemplate(petentry) : nullptr;
if (!cInfo)
{
sLog.outErrorDb("EffectSummonPet: creature entry %u not found for spell %u.", petentry, m_spellInfo->Id);
delete NewSummon; delete NewSummon;
return; return;
} }
@ -6695,69 +6683,65 @@ void Spell::EffectSummonPet(SpellEffectEntry const* effect)
NewSummon->SetRespawnCoord(pos); NewSummon->SetRespawnCoord(pos);
uint32 petlevel = m_caster->getLevel(); // Level of pet summoned
NewSummon->setPetType(SUMMON_PET); uint32 level = std::max(m_caster->getLevel() + effect->EffectMultipleValue, 1.0f);
uint32 faction = m_caster->getFaction();
if (m_caster->GetTypeId() == TYPEID_UNIT)
{
if (((Creature*)m_caster)->IsTotem())
NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
else
NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
}
NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
NewSummon->SetOwnerGuid(m_caster->GetObjectGuid()); NewSummon->SetOwnerGuid(m_caster->GetObjectGuid());
NewSummon->SetCreatorGuid(m_caster->GetObjectGuid()); NewSummon->SetCreatorGuid(m_caster->GetObjectGuid());
NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); NewSummon->setFaction(m_caster->getFaction());
NewSummon->setFaction(faction); NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(nullptr)));
NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL)));
NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true); NewSummon->InitStatsForLevel(level);
// this enables pet details window (Shift+P)
if (m_caster->IsPvP())
NewSummon->SetPvP(true);
if (m_caster->IsFFAPvP())
NewSummon->SetFFAPvP(true);
NewSummon->InitStatsForLevel(petlevel, m_caster);
NewSummon->InitPetCreateSpells(); NewSummon->InitPetCreateSpells();
NewSummon->InitLevelupSpellsForLevel(); NewSummon->InitLevelupSpellsForLevel();
NewSummon->InitTalentForLevel(); NewSummon->InitTalentForLevel();
if (m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->getPetType() == SUMMON_PET)
{
// generate new name for summon pet
std::string new_name = sObjectMgr.GeneratePetName(petentry);
if (!new_name.empty())
NewSummon->SetName(new_name);
}
if (NewSummon->getPetType() == HUNTER_PET)
{
NewSummon->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
NewSummon->SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_ABANDONED);
}
NewSummon->AIM_Initialize();
NewSummon->SetHealth(NewSummon->GetMaxHealth());
NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
map->Add((Creature*)NewSummon); map->Add((Creature*)NewSummon);
NewSummon->AIM_Initialize();
m_caster->SetPet(NewSummon); m_caster->SetPet(NewSummon);
DEBUG_LOG("New Pet has guid %u", NewSummon->GetGUIDLow()); DEBUG_LOG("New Pet has guid %u", NewSummon->GetGUIDLow());
if (m_caster->GetTypeId() == TYPEID_PLAYER) if (m_caster->GetTypeId() == TYPEID_PLAYER)
{ {
NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE | UNIT_BYTE2_FLAG_AURAS);
NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
// generate new name for summon pet
NewSummon->SetName(sObjectMgr.GeneratePetName(petentry));
if (m_caster->IsPvP())
NewSummon->SetPvP(true);
if (m_caster->IsFFAPvP())
NewSummon->SetFFAPvP(true);
NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT); NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
((Player*)m_caster)->PetSpellInitialize(); ((Player*)m_caster)->PetSpellInitialize();
} }
else
{
// Notify Summoner
if (m_originalCaster && (m_originalCaster != m_caster)
&& (m_originalCaster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_originalCaster)->AI())
{
((Creature*)m_originalCaster)->AI()->JustSummoned(NewSummon);
if (m_originalCaster->IsInCombat() && !(NewSummon->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
((Creature*)NewSummon)->AI()->AttackStart(m_originalCaster->getAttackerForHelper());
}
else if ((m_caster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_caster)->AI())
{
((Creature*)m_caster)->AI()->JustSummoned(NewSummon);
if (m_caster->IsInCombat() && !(NewSummon->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
((Creature*)NewSummon)->AI()->AttackStart(m_caster->getAttackerForHelper());
}
}
} }
void Spell::EffectLearnPetSpell(SpellEffectEntry const* effect) void Spell::EffectLearnPetSpell(SpellEffectEntry const* effect)
@ -11490,8 +11474,8 @@ void Spell::EffectActivateRune(SpellEffectEntry const* effect)
return; return;
int32 count = damage; // max amount of reset runes int32 count = damage; // max amount of reset runes
if (plr->ActivateRunes(RuneType(effect->EffectMiscValue), count))
plr->ResyncRunes(); plr->ResyncRunes();
} }
void Spell::EffectTitanGrip(SpellEffectEntry const* effect) void Spell::EffectTitanGrip(SpellEffectEntry const* effect)

View file

@ -186,6 +186,14 @@ void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recv_data)
{ {
uint32 node; uint32 node;
recv_data >> node; recv_data >> node;
if (!_player->m_taxi.IsTaximaskNodeKnown(node) && !_player->IsTaxiCheater())
{
SendActivateTaxiReply(ERR_TAXINOTVISITED);
recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet
return;
}
nodes.push_back(node); nodes.push_back(node);
} }
@ -282,5 +290,14 @@ void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recv_data)
return; return;
} }
if (!_player->IsTaxiCheater())
{
if (!_player->m_taxi.IsTaximaskNodeKnown(nodes[0]) || !_player->m_taxi.IsTaximaskNodeKnown(nodes[1]))
{
SendActivateTaxiReply(ERR_TAXINOTVISITED);
return;
}
}
GetPlayer()->ActivateTaxiPathTo(nodes, npc); GetPlayer()->ActivateTaxiPathTo(nodes, npc);
} }

View file

@ -101,12 +101,16 @@ void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket& recvPacket)
DEBUG_LOG("WORLD: Received opcode CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE"); DEBUG_LOG("WORLD: Received opcode CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE");
recvPacket.hexlike(); recvPacket.hexlike();
ObjectGuid srcVehicleGuid;
MovementInfo movementInfo; MovementInfo movementInfo;
ObjectGuid destVehicleGuid;
uint8 seat;
recvPacket >> movementInfo; // Not used at the moment recvPacket >> movementInfo;
ObjectGuid srcVehicleGuid = movementInfo.GetGuid();
ObjectGuid destVehicleGuid = movementInfo.GetGuid2(); srcVehicleGuid = movementInfo.GetGuid();
uint8 seat = movementInfo.GetByteParam(); destVehicleGuid = movementInfo.GetGuid2();
seat = movementInfo.GetByteParam();
TransportInfo* transportInfo = _player->GetTransportInfo(); TransportInfo* transportInfo = _player->GetTransportInfo();
if (!transportInfo || !transportInfo->IsOnVehicle()) if (!transportInfo || !transportInfo->IsOnVehicle())

View file

@ -34,6 +34,7 @@
#include "Log.h" #include "Log.h"
// #include "ObjectMgr.h" // chucky delete ? // #include "ObjectMgr.h" // chucky delete ?
#include "Util.h" #include "Util.h"
#include "ProgressBar.h"
#ifdef ENABLE_ELUNA #ifdef ENABLE_ELUNA
#include "LuaEngine.h" #include "LuaEngine.h"
#endif /* ENABLE_ELUNA */ #endif /* ENABLE_ELUNA */
@ -154,8 +155,8 @@ bool Weather::ReGenerate()
uint32 chance1 = m_weatherChances->data[season].rainChance; uint32 chance1 = m_weatherChances->data[season].rainChance;
uint32 chance2 = chance1 + m_weatherChances->data[season].snowChance; uint32 chance2 = chance1 + m_weatherChances->data[season].snowChance;
uint32 chance3 = chance2 + m_weatherChances->data[season].stormChance; uint32 chance3 = chance2 + m_weatherChances->data[season].stormChance;
uint32 rnd = urand(0, 99); uint32 rnd = urand(1, 100);
if (rnd <= chance1) if (rnd <= chance1)
{ {
m_type = WEATHER_TYPE_RAIN; m_type = WEATHER_TYPE_RAIN;

View file

@ -144,19 +144,17 @@ World::~World()
// it is assumed that no other thread is accessing this data when the destructor is called. therefore, no locks are necessary // it is assumed that no other thread is accessing this data when the destructor is called. therefore, no locks are necessary
///- Empty the kicked session set ///- Empty the kicked session set
std::for_each(m_sessions.begin(), m_sessions.end(), [](const SessionMap::value_type &p) { delete p.second; }); for (auto const session : m_sessions)
m_sessions.clear(); delete session.second;
std::for_each(m_cliCommandQueue.begin(), m_cliCommandQueue.end(), [](const CliCommandHolder *p) { delete p; }); for (auto const cliCommand : m_cliCommandQueue)
m_cliCommandQueue.clear(); delete cliCommand;
std::for_each(m_sessionAddQueue.begin(), m_sessionAddQueue.end(), [](const WorldSession *s) { delete s; }); for (auto const session : m_sessionAddQueue)
m_sessionAddQueue.clear(); delete session;
VMAP::VMapFactory::clear(); VMAP::VMapFactory::clear();
MMAP::MMapFactory::clear(); MMAP::MMapFactory::clear();
delete m_configForceLoadMapIds;
} }
/// Cleanups before world stop /// Cleanups before world stop
@ -577,6 +575,17 @@ void World::LoadConfigSettings(bool reload)
setConfig(CONFIG_BOOL_ADDON_CHANNEL, "AddonChannel", true); setConfig(CONFIG_BOOL_ADDON_CHANNEL, "AddonChannel", true);
setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB, "CleanCharacterDB", true); setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB, "CleanCharacterDB", true);
setConfig(CONFIG_BOOL_GRID_UNLOAD, "GridUnload", true); setConfig(CONFIG_BOOL_GRID_UNLOAD, "GridUnload", true);
std::string forceLoadGridOnMaps = sConfig.GetStringDefault("LoadAllGridsOnMaps", "");
if (!forceLoadGridOnMaps.empty())
{
unsigned int pos = 0;
unsigned int id;
VMAP::VMapFactory::chompAndTrim(forceLoadGridOnMaps);
while (VMAP::VMapFactory::getNextId(forceLoadGridOnMaps, pos, id))
m_configForceLoadMapIds.insert(id);
}
setConfig(CONFIG_UINT32_INTERVAL_SAVE, "PlayerSave.Interval", 15 * MINUTE * IN_MILLISECONDS); setConfig(CONFIG_UINT32_INTERVAL_SAVE, "PlayerSave.Interval", 15 * MINUTE * IN_MILLISECONDS);
setConfigMinMax(CONFIG_UINT32_MIN_LEVEL_STAT_SAVE, "PlayerSave.Stats.MinLevel", 0, 0, MAX_LEVEL); setConfigMinMax(CONFIG_UINT32_MIN_LEVEL_STAT_SAVE, "PlayerSave.Stats.MinLevel", 0, 0, MAX_LEVEL);
setConfig(CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT, "PlayerSave.Stats.SaveOnlyOnLogout", true); setConfig(CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT, "PlayerSave.Stats.SaveOnlyOnLogout", true);
@ -635,7 +644,7 @@ void World::LoadConfigSettings(bool reload)
if (configNoReload(reload, CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL)) if (configNoReload(reload, CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL))
{ setConfigMinMax(CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL, 1, DEFAULT_MAX_LEVEL); } { setConfigMinMax(CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL, 1, DEFAULT_MAX_LEVEL); }
setConfigMinMax(CONFIG_UINT32_START_PLAYER_LEVEL, "StartPlayerLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)); setConfigMinMax(CONFIG_UINT32_START_PLAYER_LEVEL, "StartPlayerLevel", 1, 1, (uint32)getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
setConfigMinMax(CONFIG_UINT32_START_HEROIC_PLAYER_LEVEL, "StartHeroicPlayerLevel", 55, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)); setConfigMinMax(CONFIG_UINT32_START_HEROIC_PLAYER_LEVEL, "StartHeroicPlayerLevel", 55, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
setConfigMinMax(CONFIG_UINT64_START_PLAYER_MONEY, "StartPlayerMoney", 0, 0, MAX_MONEY_AMOUNT); setConfigMinMax(CONFIG_UINT64_START_PLAYER_MONEY, "StartPlayerMoney", 0, 0, MAX_MONEY_AMOUNT);
@ -787,6 +796,7 @@ void World::LoadConfigSettings(bool reload)
setConfig(CONFIG_BOOL_BATTLEGROUND_CAST_DESERTER, "Battleground.CastDeserter", true); setConfig(CONFIG_BOOL_BATTLEGROUND_CAST_DESERTER, "Battleground.CastDeserter", true);
setConfigMinMax(CONFIG_UINT32_BATTLEGROUND_QUEUE_ANNOUNCER_JOIN, "Battleground.QueueAnnouncer.Join", 0, 0, 2); setConfigMinMax(CONFIG_UINT32_BATTLEGROUND_QUEUE_ANNOUNCER_JOIN, "Battleground.QueueAnnouncer.Join", 0, 0, 2);
setConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_START, "Battleground.QueueAnnouncer.Start", false); setConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_START, "Battleground.QueueAnnouncer.Start", false);
setConfig(CONFIG_BOOL_BATTLEGROUND_SCORE_STATISTICS, "Battleground.ScoreStatistics", false);
setConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE, "Battleground.InvitationType", 0); setConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE, "Battleground.InvitationType", 0);
setConfig(CONFIG_UINT32_BATTLEGROUND_PREMATURE_FINISH_TIMER, "BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILLISECONDS); setConfig(CONFIG_UINT32_BATTLEGROUND_PREMATURE_FINISH_TIMER, "BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILLISECONDS);
setConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH, "BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILLISECONDS); setConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH, "BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILLISECONDS);

View file

@ -612,6 +612,9 @@ class World
/// Get a server configuration element (see #eConfigBoolValues) /// Get a server configuration element (see #eConfigBoolValues)
bool getConfig(eConfigBoolValues index) const { return m_configBoolValues[index]; } bool getConfig(eConfigBoolValues index) const { return m_configBoolValues[index]; }
/// Get configuration about force-loaded maps
bool isForceLoadMap(uint32 id) const { return m_configForceLoadMapIds.find(id) != m_configForceLoadMapIds.end(); }
/// Are we on a "Player versus Player" server? /// Are we on a "Player versus Player" server?
bool IsPvPRealm() { return (getConfig(CONFIG_UINT32_GAME_TYPE) == REALM_TYPE_PVP || getConfig(CONFIG_UINT32_GAME_TYPE) == REALM_TYPE_RPPVP || getConfig(CONFIG_UINT32_GAME_TYPE) == REALM_TYPE_FFA_PVP); } bool IsPvPRealm() { return (getConfig(CONFIG_UINT32_GAME_TYPE) == REALM_TYPE_PVP || getConfig(CONFIG_UINT32_GAME_TYPE) == REALM_TYPE_RPPVP || getConfig(CONFIG_UINT32_GAME_TYPE) == REALM_TYPE_FFA_PVP); }
bool IsFFAPvPRealm() { return getConfig(CONFIG_UINT32_GAME_TYPE) == REALM_TYPE_FFA_PVP; } bool IsFFAPvPRealm() { return getConfig(CONFIG_UINT32_GAME_TYPE) == REALM_TYPE_FFA_PVP; }
@ -766,9 +769,10 @@ class World
// used versions // used versions
std::string m_DBVersion; std::string m_DBVersion;
std::string m_CreatureEventAIVersion;
// List of Maps that should be force-loaded on startup // List of Maps that should be force-loaded on startup
std::set<uint32>* m_configForceLoadMapIds; std::set<uint32> m_configForceLoadMapIds;
}; };
extern uint32 realmID; extern uint32 realmID;

View file

@ -171,7 +171,7 @@ namespace Movement
{ {
// mix existing state into new // mix existing state into new
args.flags.walkmode = unit.m_movementInfo.HasMovementFlag(MOVEFLAG_WALK_MODE); args.flags.walkmode = unit.m_movementInfo.HasMovementFlag(MOVEFLAG_WALK_MODE);
args.flags.flying = unit.m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_FLYING | MOVEFLAG_LEVITATING)); args.flags.flying = unit.m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_CAN_FLY | MOVEFLAG_FLYING | MOVEFLAG_LEVITATING));
} }
void MoveSplineInit::SetFacing(const Unit* target) void MoveSplineInit::SetFacing(const Unit* target)

View file

@ -43,7 +43,7 @@ namespace Movement
* @brief Initializes and launches spline movement * @brief Initializes and launches spline movement
* *
*/ */
class MoveSplineInit class MANGOS_DLL_SPEC MoveSplineInit
{ {
public: public:

View file

@ -30,7 +30,7 @@ using namespace G3D;
namespace VMAP namespace VMAP
{ {
void chompAndTrim(std::string& str) void VMapFactory::chompAndTrim(std::string& str)
{ {
while (str.length() > 0) while (str.length() > 0)
{ {
@ -64,7 +64,7 @@ namespace VMAP
//=============================================== //===============================================
// result false, if no more id are found // result false, if no more id are found
bool getNextId(const std::string& pString, unsigned int& pStartPos, unsigned int& pId) bool VMapFactory::getNextId(const std::string& pString, unsigned int& pStartPos, unsigned int& pId)
{ {
bool result = false; bool result = false;
unsigned int i; unsigned int i;

View file

@ -43,6 +43,9 @@ namespace VMAP
static void preventSpellsFromBeingTestedForLoS(const char* pSpellIdString); static void preventSpellsFromBeingTestedForLoS(const char* pSpellIdString);
static bool checkSpellForLoS(unsigned int pSpellId); static bool checkSpellForLoS(unsigned int pSpellId);
static void chompAndTrim(std::string& str);
static bool getNextId(const std::string& pString, unsigned int& pStartPos, unsigned int& pId);
}; };
} }
#endif #endif

View file

@ -113,6 +113,12 @@ BindIP = "0.0.0.0"
# Default: 1 (unload grids) # Default: 1 (unload grids)
# 0 (do not unload grids) # 0 (do not unload grids)
# #
# LoadAllGridsOnMaps
# Load grids of maps at server startup (if you have lot memory you can try it to have a living world always loaded)
# This also allow ALL creatures on the given maps to update their grid without any player around.
# Default: "" (don't load all grids at startup)
# "mapId1[,mapId2[..]]" (DO load all grids on the given maps- Experimental and very resource consumming)
#
# GridCleanUpDelay # GridCleanUpDelay
# Grid clean up delay (in milliseconds) # Grid clean up delay (in milliseconds)
# Default: 300000 (5 min) # Default: 300000 (5 min)
@ -207,6 +213,7 @@ PlayerLimit = 100
SaveRespawnTimeImmediately = 1 SaveRespawnTimeImmediately = 1
MaxOverspeedPings = 2 MaxOverspeedPings = 2
GridUnload = 1 GridUnload = 1
LoadAllGridsOnMaps = ""
GridCleanUpDelay = 300000 GridCleanUpDelay = 300000
MapUpdateInterval = 100 MapUpdateInterval = 100
ChangeWeatherInterval = 600000 ChangeWeatherInterval = 600000
@ -1487,6 +1494,11 @@ Death.Ghost.RunSpeed.Battleground = 1.0
# 1 (send to joined player only) # 1 (send to joined player only)
# 2 (send to all players) # 2 (send to all players)
# #
# Battleground.ScoreStatistics
# Enable Battleground scores storage in database
# Default: 0 (disable)
# 1 (enable)
#
# Battleground.QueueAnnouncer.Start # Battleground.QueueAnnouncer.Start
# Enable queue announcer posting to chat at BG start # Enable queue announcer posting to chat at BG start
# Default: 0 (disable) # Default: 0 (disable)
@ -1512,6 +1524,7 @@ Death.Ghost.RunSpeed.Battleground = 1.0
Battleground.CastDeserter = 1 Battleground.CastDeserter = 1
Battleground.QueueAnnouncer.Join = 0 Battleground.QueueAnnouncer.Join = 0
Battleground.QueueAnnouncer.Start = 0 Battleground.QueueAnnouncer.Start = 0
Battleground.ScoreStatistics = 0
Battleground.InvitationType = 0 Battleground.InvitationType = 0
BattleGround.PrematureFinishTimer = 300000 BattleGround.PrematureFinishTimer = 300000
BattleGround.PremadeGroupWaitForMatch = 1800000 BattleGround.PremadeGroupWaitForMatch = 1800000

View file

@ -105,7 +105,7 @@ namespace LuaUnit
Creature* creature = Eluna::CHECKOBJ<Creature>(L, 2); Creature* creature = Eluna::CHECKOBJ<Creature>(L, 2);
#ifndef TRINITY #ifndef TRINITY
Eluna::Push(L, unit->isInAccessablePlaceFor(creature)); Eluna::Push(L, unit->IsInAccessablePlaceFor(creature));
#else #else
Eluna::Push(L, unit->isInAccessiblePlaceFor(creature)); Eluna::Push(L, unit->isInAccessiblePlaceFor(creature));
#endif #endif
@ -1707,12 +1707,12 @@ namespace LuaUnit
if (apply) if (apply)
{ {
unit->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); unit->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE);
unit->CombatStop(); unit->CombatStop();
unit->CombatStopWithPets(); unit->CombatStopWithPets();
} }
else else
unit->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); unit->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE);
return 0; return 0;
} }

View file

@ -184,7 +184,7 @@ bool npc_escortAI::AssistPlayerInCombat(Unit* pWho)
void npc_escortAI::MoveInLineOfSight(Unit* pWho) void npc_escortAI::MoveInLineOfSight(Unit* pWho)
{ {
if (pWho->IsTargetableForAttack() && pWho->isInAccessablePlaceFor(m_creature)) if (pWho->IsTargetableForAttack() && pWho->IsInAccessablePlaceFor(m_creature))
{ {
// AssistPlayerInCombat can start attack, so return if true // AssistPlayerInCombat can start attack, so return if true
if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombat(pWho)) if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombat(pWho))

View file

@ -122,7 +122,7 @@ bool FollowerAI::AssistPlayerInCombat(Unit* pWho)
void FollowerAI::MoveInLineOfSight(Unit* pWho) void FollowerAI::MoveInLineOfSight(Unit* pWho)
{ {
if (pWho->IsTargetableForAttack() && pWho->isInAccessablePlaceFor(m_creature)) if (pWho->IsTargetableForAttack() && pWho->IsInAccessablePlaceFor(m_creature))
{ {
// AssistPlayerInCombat can start attack, so return if true // AssistPlayerInCombat can start attack, so return if true
if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombat(pWho)) if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombat(pWho))

View file

@ -56,7 +56,7 @@ void ScriptedPetAI::MoveInLineOfSight(Unit* pWho)
} }
if (m_creature->CanInitiateAttack() && pWho->IsTargetableForAttack() && if (m_creature->CanInitiateAttack() && pWho->IsTargetableForAttack() &&
m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) m_creature->IsHostileTo(pWho) && pWho->IsInAccessablePlaceFor(m_creature))
{ {
if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE)
{ {

View file

@ -74,7 +74,7 @@ bool ScriptedAI::IsVisible(Unit* pWho) const
void ScriptedAI::MoveInLineOfSight(Unit* pWho) void ScriptedAI::MoveInLineOfSight(Unit* pWho)
{ {
if (m_creature->CanInitiateAttack() && pWho->IsTargetableForAttack() && if (m_creature->CanInitiateAttack() && pWho->IsTargetableForAttack() &&
m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) m_creature->IsHostileTo(pWho) && pWho->IsInAccessablePlaceFor(m_creature))
{ {
if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE)
{ {

View file

@ -59,14 +59,14 @@ struct npc_ragged_john : public CreatureScript
{ {
if (who->HasAura(16468, EFFECT_INDEX_0)) if (who->HasAura(16468, EFFECT_INDEX_0))
{ {
if (who->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(who, 15) && who->isInAccessablePlaceFor(m_creature)) if (who->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(who, 15) && who->IsInAccessablePlaceFor(m_creature))
{ {
DoCastSpellIfCan(who, 16472); DoCastSpellIfCan(who, 16472);
((Player*)who)->AreaExploredOrEventHappens(4866); ((Player*)who)->AreaExploredOrEventHappens(4866);
} }
} }
if (!m_creature->getVictim() && who->IsTargetableForAttack() && (m_creature->IsHostileTo(who)) && who->isInAccessablePlaceFor(m_creature)) if (!m_creature->getVictim() && who->IsTargetableForAttack() && (m_creature->IsHostileTo(who)) && who->IsInAccessablePlaceFor(m_creature))
{ {
if (!m_creature->CanFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) if (!m_creature->CanFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
{ {

View file

@ -1247,7 +1247,7 @@ struct horde_defender : public CreatureScript
void MoveInLineOfSight(Unit* u) override void MoveInLineOfSight(Unit* u) override
{ {
if (m_creature->CanInitiateAttack() && u->IsTargetableForAttack() && if (m_creature->CanInitiateAttack() && u->IsTargetableForAttack() &&
m_creature->IsHostileTo(u) && u->isInAccessablePlaceFor(m_creature)) m_creature->IsHostileTo(u) && u->IsInAccessablePlaceFor(m_creature))
{ {
float attackRadius = 38.0f; float attackRadius = 38.0f;
if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->IsWithinLOSInMap(u)) if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->IsWithinLOSInMap(u))
@ -1330,7 +1330,7 @@ struct kolkar_invader : public CreatureScript
void MoveInLineOfSight(Unit* u) override void MoveInLineOfSight(Unit* u) override
{ {
if (m_creature->CanInitiateAttack() && u->IsTargetableForAttack() && if (m_creature->CanInitiateAttack() && u->IsTargetableForAttack() &&
m_creature->IsHostileTo(u) && u->isInAccessablePlaceFor(m_creature)) m_creature->IsHostileTo(u) && u->IsInAccessablePlaceFor(m_creature))
{ {
float attackRadius = 38.0f; float attackRadius = 38.0f;
if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->IsWithinLOSInMap(u)) if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->IsWithinLOSInMap(u))

View file

@ -100,7 +100,7 @@ struct boss_talon_king_ikiss : public CreatureScript
void MoveInLineOfSight(Unit* pWho) override void MoveInLineOfSight(Unit* pWho) override
{ {
if (!m_creature->getVictim() && pWho->IsTargetableForAttack() && (m_creature->IsHostileTo(pWho)) && pWho->isInAccessablePlaceFor(m_creature)) if (!m_creature->getVictim() && pWho->IsTargetableForAttack() && (m_creature->IsHostileTo(pWho)) && pWho->IsInAccessablePlaceFor(m_creature))
{ {
if (!m_bIntro && m_creature->IsWithinDistInMap(pWho, 100.0f)) if (!m_bIntro && m_creature->IsWithinDistInMap(pWho, 100.0f))
{ {

View file

@ -179,9 +179,12 @@ struct npc_ancestral_wolf : public CreatureScript
void Reset() override void Reset() override
{ {
m_creature->CastSpell(m_creature, SPELL_ANCESTRAL_WOLF_BUFF, true); DoCastSpellIfCan(m_creature, SPELL_ANCESTRAL_WOLF_BUFF);
} }
void AttackStart(Unit* /*pWho*/) override { }
void MoveInLineOfSight(Unit* /*pWho*/) override { }
void WaypointReached(uint32 uiPointId) override void WaypointReached(uint32 uiPointId) override
{ {
switch (uiPointId) switch (uiPointId)

View file

@ -72,7 +72,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <math.h> #include <cmath>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <assert.h> #include <assert.h>
@ -172,7 +172,7 @@ typedef off_t ACE_OFF_T;
* @param f * @param f
* @return float * @return float
*/ */
inline float finiteAlways(float f) { return finite(f) ? f : 0.0f; } inline float finiteAlways(float f) { return std::isfinite(f) ? f : 0.0f; }
#define atol(a) strtoul( a, NULL, 10) #define atol(a) strtoul( a, NULL, 10)

View file

@ -65,7 +65,7 @@ uint32 WorldTimer::getMSTime_internal(bool savetime /*= false*/)
// calculate time diff between two world ticks // calculate time diff between two world ticks
// special case: curr_time < old_time - we suppose that our time has not ticked at all // special case: curr_time < old_time - we suppose that our time has not ticked at all
// this should be constant value otherwise it is possible that our time can start ticking backwards until next world tick!!! // this should be constant value otherwise it is possible that our time can start ticking backwards until next world tick!!!
uint64 diff = 0; ACE_UINT64 diff = 0;
(currTime - g_SystemTickTime).msec(diff); (currTime - g_SystemTickTime).msec(diff);
// lets calculate current world time // lets calculate current world time

View file

@ -33,11 +33,11 @@
#define CHAR_DB_VERSION_NR 21 #define CHAR_DB_VERSION_NR 21
#define CHAR_DB_STRUCTURE_NR 2 #define CHAR_DB_STRUCTURE_NR 2
#define CHAR_DB_CONTENT_NR 1 #define CHAR_DB_CONTENT_NR 2
#define CHAR_DB_UPDATE_DESCRIPTION "match_client_limits" #define CHAR_DB_UPDATE_DESCRIPTION "match_client_limits"
#define WORLD_DB_VERSION_NR 21 #define WORLD_DB_VERSION_NR 21
#define WORLD_DB_STRUCTURE_NR 1 #define WORLD_DB_STRUCTURE_NR 2
#define WORLD_DB_CONTENT_NR 0 #define WORLD_DB_CONTENT_NR 3
#define WORLD_DB_UPDATE_DESCRIPTION "script_binding populated" #define WORLD_DB_UPDATE_DESCRIPTION "script_binding populated"
#endif // __REVISION_H__ #endif // __REVISION_H__

View file

@ -67,19 +67,11 @@ else()
target_link_libraries(${EXECUTABLE_NAME} ACE) target_link_libraries(${EXECUTABLE_NAME} ACE)
endif() endif()
target_link_libraries(${EXECUTABLE_NAME} g3dlite vmap detour recast zlib shared)
if(UNIX) if(UNIX)
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") target_link_libraries(${EXECUTABLE_NAME} rt)
set(EXECUTABLE_LINK_FLAGS "-Wl,--no-as-needed -lrt -pthread ${EXECUTABLE_LINK_FLAGS}")
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
set(EXECUTABLE_LINK_FLAGS "-Wl,--no-as-needed -ldl -pthread -lrt ${EXECUTABLE_LINK_FLAGS}")
endif()
endif() endif()
if(APPLE) target_link_libraries(${EXECUTABLE_NAME} g3dlite vmap detour recast zlib shared)
set(EXECUTABLE_LINK_FLAGS "-framework CoreServices ${EXECUTABLE_LINK_FLAGS}")
endif()
#Output the compiled exes to build/bin/$(Configuration)/tools directory on windows by default #Output the compiled exes to build/bin/$(Configuration)/tools directory on windows by default
if(WIN32) if(WIN32)

View file

@ -47,22 +47,20 @@ else()
target_link_libraries(${EXECUTABLE_NAME} ACE) target_link_libraries(${EXECUTABLE_NAME} ACE)
endif() endif()
if(UNIX)
target_link_libraries(${EXECUTABLE_NAME} rt dl)
endif()
target_link_libraries(${EXECUTABLE_NAME} vmap g3dlite zlib) target_link_libraries(${EXECUTABLE_NAME} vmap g3dlite zlib)
set(EXECUTABLE_LINK_FLAGS "") set(EXECUTABLE_LINK_FLAGS "")
if(UNIX) if(UNIX)
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") if(CMAKE_C_COMPILER MATCHES "clang" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(EXECUTABLE_LINK_FLAGS "-Wl,--no-as-needed -lrt -pthread ${EXECUTABLE_LINK_FLAGS}") set(EXECUTABLE_LINK_FLAGS "-pthread${EXECUTABLE_LINK_FLAGS}")
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
set(EXECUTABLE_LINK_FLAGS "-Wl,--no-as-needed -ldl -pthread -lrt ${EXECUTABLE_LINK_FLAGS}")
endif() endif()
endif() endif()
if(APPLE)
set(EXECUTABLE_LINK_FLAGS "-framework CoreServices ${EXECUTABLE_LINK_FLAGS}")
endif()
set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "${EXECUTABLE_LINK_FLAGS}") set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "${EXECUTABLE_LINK_FLAGS}")
#Output the compiled exes to build/bin/$(Configuration)/tools directory on windows by default #Output the compiled exes to build/bin/$(Configuration)/tools directory on windows by default

View file

@ -43,7 +43,7 @@ add_executable(${EXECUTABLE_NAME} ${EXECUTABLE_SRCS}
${CMAKE_SOURCE_DIR}/src/tools/Extractor_projects/shared/ExtractorCommon.cpp ${CMAKE_SOURCE_DIR}/src/tools/Extractor_projects/shared/ExtractorCommon.cpp
) )
target_link_libraries(${EXECUTABLE_NAME} StormLib loadlib bzip2 zlib) target_link_libraries(${EXECUTABLE_NAME} loadlib bzip2 zlib StormLib)
#Output the compiled exes to build/bin/$(Configuration)/tools directory on windows by default #Output the compiled exes to build/bin/$(Configuration)/tools directory on windows by default
if(WIN32) if(WIN32)