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_Map = NULL;
m_TeamStartLocX[BG_TEAM_ALLIANCE] = 0;
m_TeamStartLocX[BG_TEAM_HORDE] = 0;
m_TeamStartLocX[TEAM_INDEX_ALLIANCE] = 0;
m_TeamStartLocX[TEAM_INDEX_HORDE] = 0;
m_TeamStartLocY[BG_TEAM_ALLIANCE] = 0;
m_TeamStartLocY[BG_TEAM_HORDE] = 0;
m_TeamStartLocY[TEAM_INDEX_ALLIANCE] = 0;
m_TeamStartLocY[TEAM_INDEX_HORDE] = 0;
m_TeamStartLocZ[BG_TEAM_ALLIANCE] = 0;
m_TeamStartLocZ[BG_TEAM_HORDE] = 0;
m_TeamStartLocZ[TEAM_INDEX_ALLIANCE] = 0;
m_TeamStartLocZ[TEAM_INDEX_HORDE] = 0;
m_TeamStartLocO[BG_TEAM_ALLIANCE] = 0;
m_TeamStartLocO[BG_TEAM_HORDE] = 0;
m_TeamStartLocO[TEAM_INDEX_ALLIANCE] = 0;
m_TeamStartLocO[TEAM_INDEX_HORDE] = 0;
m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0;
m_ArenaTeamIds[BG_TEAM_HORDE] = 0;
m_ArenaTeamIds[TEAM_INDEX_ALLIANCE] = 0;
m_ArenaTeamIds[TEAM_INDEX_HORDE] = 0;
m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0;
m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0;
m_ArenaTeamRatingChanges[TEAM_INDEX_ALLIANCE] = 0;
m_ArenaTeamRatingChanges[TEAM_INDEX_HORDE] = 0;
m_BgRaids[BG_TEAM_ALLIANCE] = NULL;
m_BgRaids[BG_TEAM_HORDE] = NULL;
m_BgRaids[TEAM_INDEX_ALLIANCE] = NULL;
m_BgRaids[TEAM_INDEX_HORDE] = NULL;
m_PlayersCount[BG_TEAM_ALLIANCE] = 0;
m_PlayersCount[BG_TEAM_HORDE] = 0;
m_PlayersCount[TEAM_INDEX_ALLIANCE] = 0;
m_PlayersCount[TEAM_INDEX_HORDE] = 0;
m_TeamScores[BG_TEAM_ALLIANCE] = 0;
m_TeamScores[BG_TEAM_HORDE] = 0;
m_TeamScores[TEAM_INDEX_ALLIANCE] = 0;
m_TeamScores[TEAM_INDEX_HORDE] = 0;
m_PrematureCountDown = false;
m_PrematureCountDownTimer = 0;
@ -459,6 +459,14 @@ void BattleGround::Update(uint32 diff)
/*********************************************************/
/*** 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)
{
@ -485,7 +493,7 @@ void BattleGround::Update(uint32 diff)
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_TeamStartLocY[teamIdx] = Y;
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
void BattleGround::EventPlayerLoggedIn(Player* player, ObjectGuid plr_guid)
void BattleGround::EventPlayerLoggedIn(Player* player)
{
ObjectGuid playerGuid = player->GetObjectGuid();
// player is correct pointer
for (OfflineQueue::iterator itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr)
{
if (*itr == plr_guid)
if (*itr == playerGuid)
{
m_OfflineQueue.erase(itr);
break;
}
}
m_Players[plr_guid].OfflineRemoveTime = 0;
m_Players[playerGuid].OfflineRemoveTime = 0;
PlayerAddedToBGCheckIfBGIsRunning(player);
// 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
@ -1783,7 +1793,7 @@ WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard(Player* player)
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]);
return score >= minScore && score <= maxScore;
}

View file

@ -112,13 +112,14 @@ enum BattleGroundTimeIntervals
{
RESURRECTION_INTERVAL = 30000, // ms
INVITATION_REMIND_TIME = 20000, // ms
INVITE_ACCEPT_WAIT_TIME = 40000, // ms
INVITE_ACCEPT_WAIT_TIME = 60000, // ms
TIME_TO_AUTOREMOVE = 120000, // ms
MAX_OFFLINE_TIME = 300, // secs
RESPAWN_ONE_DAY = 86400, // secs
RESPAWN_IMMEDIATELY = 0, // secs
BUFF_RESPAWN_TIME = 180, // secs
ARENA_SPAWN_BUFF_OBJECTS = 90000, // ms - 90sec after start
ARENA_FORCED_DRAW = 2700000, // ms - 45min after start
BATTLEGROUND_COUNTDOWN_MAX = 120, // secs
ARENA_COUNTDOWN_MAX = 60, // secs
};
@ -212,14 +213,6 @@ enum BattleGroundType
TYPE_ARENA = 4
};
enum BattleGroundTeamIndex
{
BG_TEAM_ALLIANCE = 0,
BG_TEAM_HORDE = 1
};
#define BG_TEAMS_COUNT 2
enum BattleGroundStartingEvents
{
BG_STARTING_EVENT_NONE = 0x00,
@ -432,7 +425,7 @@ class BattleGround
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
{
BattleGroundTeamIndex idx = GetTeamIndexByTeamId(team);
PvpTeamIndex idx = GetTeamIndexByTeamId(team);
X = m_TeamStartLocX[idx];
Y = m_TeamStartLocY[idx];
Z = m_TeamStartLocZ[idx];
@ -477,7 +470,7 @@ class BattleGround
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 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)
@ -518,7 +511,7 @@ class BattleGround
virtual void EventPlayerDroppedFlag(Player* /*player*/) {}
virtual void EventPlayerClickedOnFlag(Player* /*player*/, GameObject* /*target_obj*/) {}
virtual void EventPlayerCapturedFlag(Player* /*player*/) {}
void EventPlayerLoggedIn(Player* player, ObjectGuid plr_guid);
void EventPlayerLoggedIn(Player* player);
void EventPlayerLoggedOut(Player* player);
/* Death related */
@ -563,11 +556,11 @@ class BattleGround
Team GetPlayerTeam(ObjectGuid guid);
uint32 GetRemainingTime() const { return m_EndTime; }
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);
/* virtual score-array - get's used in bg-subclasses */
int32 m_TeamScores[BG_TEAMS_COUNT];
int32 m_TeamScores[PVP_TEAM_COUNT];
struct EventObjects
{
@ -640,15 +633,15 @@ class BattleGround
uint32 m_InvitedHorde;
/* 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 */
uint32 m_PlayersCount[BG_TEAMS_COUNT];
uint32 m_PlayersCount[PVP_TEAM_COUNT];
/* 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 */
uint32 m_LevelMin;
@ -661,10 +654,10 @@ class BattleGround
/* Start location */
uint32 m_MapId;
BattleGroundMap* m_Map;
float m_TeamStartLocX[BG_TEAMS_COUNT];
float m_TeamStartLocY[BG_TEAMS_COUNT];
float m_TeamStartLocZ[BG_TEAMS_COUNT];
float m_TeamStartLocO[BG_TEAMS_COUNT];
float m_TeamStartLocX[PVP_TEAM_COUNT];
float m_TeamStartLocY[PVP_TEAM_COUNT];
float m_TeamStartLocZ[PVP_TEAM_COUNT];
float m_TeamStartLocO[PVP_TEAM_COUNT];
};
// helper functions for world state list fill

View file

@ -53,7 +53,7 @@ void BattleGroundAB::Update(uint32 diff)
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)
{
@ -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)
++team_points[team];
}
// 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];
if (!points)
@ -120,17 +120,17 @@ void BattleGroundAB::Update(uint32 diff)
m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
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;
}
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;
}
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);
else
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)
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]);
if (team == BG_TEAM_HORDE)
if (team == TEAM_INDEX_HORDE)
UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]);
// update achievement flags
// 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
uint8 otherTeam = (team + 1) % BG_TEAMS_COUNT;
uint8 otherTeam = (team + 1) % PVP_TEAM_COUNT;
if (m_TeamScores[team] > m_TeamScores[otherTeam] + 500)
m_TeamScores500Disadvantage[otherTeam] = true;
}
}
// 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);
if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE)
if (m_TeamScores[TEAM_INDEX_HORDE] >= BG_AB_MAX_TEAM_SCORE)
EndBattleGround(HORDE);
}
}
@ -277,8 +277,8 @@ void BattleGroundAB::FillInitialWorldStates(WorldPacket& data, uint32& count)
// Team scores
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_ALLY, m_TeamScores[BG_TEAM_ALLIANCE]);
FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_HORDE, m_TeamScores[BG_TEAM_HORDE]);
FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_ALLY, m_TeamScores[TEAM_INDEX_ALLIANCE]);
FillInitialWorldState(data, count, BG_AB_OP_RESOURCES_HORDE, m_TeamScores[TEAM_INDEX_HORDE]);
// other unknown
FillInitialWorldState(data, count, 0x745, 0x2); // 37 1861 unk
@ -333,7 +333,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player* source, GameObject* target
return;
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
if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node] % 2))
@ -376,7 +376,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player* source, GameObject* target
_SendNodeUpdate(node);
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));
else
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);
_SendNodeUpdate(node);
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));
else
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
else
@ -411,18 +411,18 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player* source, GameObject* target
_SendNodeUpdate(node);
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));
else
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 (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));
else
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
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_lastTick[i] = 0;
@ -477,7 +477,7 @@ void BattleGroundAB::EndBattleGround(Team winner)
WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player)
{
BattleGroundTeamIndex teamIndex = GetTeamIndexByTeamId(player->GetTeam());
PvpTeamIndex teamIndex = GetTeamIndexByTeamId(player->GetTeam());
// Is there any occupied node for this team?
std::vector<uint8> nodes;

View file

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

View file

@ -78,7 +78,7 @@ void BattleGroundAV::HandleKillUnit(Creature* creature, Player* killer)
return;
RewardReputationToTeam(BG_AV_FACTION_H, m_RepCaptain, 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
SpawnEvent(BG_AV_NodeEventCaptainDead_A, 0, true);
break;
@ -87,7 +87,7 @@ void BattleGroundAV::HandleKillUnit(Creature* creature, Player* killer)
return;
RewardReputationToTeam(BG_AV_FACTION_A, m_RepCaptain, 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
SpawnEvent(BG_AV_NodeEventCaptainDead_H, 0, true);
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());
}
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
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
if (points < 0)
@ -223,17 +223,17 @@ void BattleGroundAV::UpdateScore(BattleGroundTeamIndex teamIdx, int32 points)
{
m_TeamScores[teamIdx] = 0;
// 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)
{
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);
m_IsInformedNearLose[teamIdx] = true;
}
}
// 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)
@ -251,7 +251,7 @@ void BattleGroundAV::Update(uint32 diff)
m_Mine_Timer[mine] -= diff;
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;
}
@ -296,18 +296,18 @@ void BattleGroundAV::AddPlayer(Player* plr)
void BattleGroundAV::EndBattleGround(Team winner)
{
// calculate bonuskills for both teams:
uint32 tower_survived[BG_TEAMS_COUNT] = {0, 0};
uint32 graves_owned[BG_TEAMS_COUNT] = {0, 0};
uint32 mines_owned[BG_TEAMS_COUNT] = {0, 0};
uint32 tower_survived[PVP_TEAM_COUNT] = {0, 0};
uint32 graves_owned[PVP_TEAM_COUNT] = {0, 0};
uint32 mines_owned[PVP_TEAM_COUNT] = {0, 0};
// towers all not destroyed:
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].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)
if (m_Nodes[i].State == POINT_CONTROLLED)
if (m_Nodes[i].TotalOwner == BG_AV_TEAM_HORDE)
++tower_survived[BG_TEAM_HORDE];
++tower_survived[TEAM_INDEX_HORDE];
// graves all controlled
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]];
// now we have the values give the honor/reputation to the teams:
Team team[BG_TEAMS_COUNT] = { ALLIANCE, HORDE };
uint32 faction[BG_TEAMS_COUNT] = { BG_AV_FACTION_A, BG_AV_FACTION_H };
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i)
Team team[PVP_TEAM_COUNT] = { ALLIANCE, HORDE };
uint32 faction[PVP_TEAM_COUNT] = { BG_AV_FACTION_A, BG_AV_FACTION_H };
for (uint8 i = 0; i < PVP_TEAM_COUNT; ++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);
MANGOS_ASSERT(m_Nodes[node].Owner != BG_AV_TEAM_NEUTRAL)
BattleGroundTeamIndex ownerTeamIdx = BattleGroundTeamIndex(m_Nodes[node].Owner);
Team ownerTeam = ownerTeamIdx == BG_TEAM_ALLIANCE ? ALLIANCE : HORDE;
PvpTeamIndex ownerTeamIdx = PvpTeamIndex(m_Nodes[node].Owner);
Team ownerTeam = ownerTeamIdx == TEAM_INDEX_ALLIANCE ? ALLIANCE : HORDE;
// despawn banner
DestroyNode(node);
@ -531,7 +531,7 @@ void BattleGroundAV::EventPlayerDefendsPoint(Player* player, BG_AV_Nodes node)
{
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)
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),
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);
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),
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);
// 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)
{
// TODO implement quest 7101, 7081
BattleGroundTeamIndex teamIdx = GetTeamIndexByTeamId(player->GetTeam());
PvpTeamIndex teamIdx = GetTeamIndexByTeamId(player->GetTeam());
DEBUG_LOG("BattleGroundAV: player assaults node %i", node);
if (m_Nodes[node].Owner == BattleGroundAVTeamIndex(teamIdx) || BattleGroundAVTeamIndex(teamIdx) == m_Nodes[node].TotalOwner)
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),
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);
}
else
{
SendYell2ToAll(LANG_BG_AV_GRAVE_ASSAULTED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
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
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)
@ -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
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_Horde_Score, m_TeamScores[BG_TEAM_HORDE]);
FillInitialWorldState(data, count, BG_AV_Alliance_Score, m_TeamScores[TEAM_INDEX_ALLIANCE]);
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
{
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].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;
}
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].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_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
m_Team_QuestStatus[i][j] = 0;

View file

@ -208,13 +208,13 @@ enum BG_AV_WorldStates
AV_SNOWFALL_N = 1966,
};
// special version with more wide values range that BattleGroundTeamIndex
// BattleGroundAVTeamIndex <- BattleGroundTeamIndex cast safe
// BattleGroundAVTeamIndex -> BattleGroundTeamIndex cast safe and array with BG_TEAMS_COUNT elements must checked != BG_AV_TEAM_NEUTRAL before used
// special version with more wide values range that PvpTeamIndex
// BattleGroundAVTeamIndex <- PvpTeamIndex cast safe
// BattleGroundAVTeamIndex -> PvpTeamIndex cast safe and array with PVP_TEAM_COUNT elements must checked != BG_AV_TEAM_NEUTRAL before used
enum BattleGroundAVTeamIndex
{
BG_AV_TEAM_ALLIANCE = BG_TEAM_ALLIANCE,
BG_AV_TEAM_HORDE = BG_TEAM_HORDE,
BG_AV_TEAM_ALLIANCE = TEAM_INDEX_ALLIANCE,
BG_AV_TEAM_HORDE = TEAM_INDEX_HORDE,
BG_AV_TEAM_NEUTRAL = 2, // this is the neutral owner of snowfall
};
@ -311,6 +311,13 @@ class BattleGroundAVScore : public BattleGroundScore
public:
BattleGroundAVScore() : GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), SecondaryObjectives(0) {};
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 GraveyardsDefended;
uint32 TowersAssaulted;
@ -337,7 +344,7 @@ class BattleGroundAV : public BattleGround
virtual void Reset() override;
/*general stuff*/
void UpdateScore(BattleGroundTeamIndex teamIdx, int32 points);
void UpdateScore(PvpTeamIndex teamIdx, int32 points);
void UpdatePlayerScore(Player* source, uint32 type, uint32 value) override;
/*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 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 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);
@ -378,7 +385,7 @@ class BattleGroundAV : public BattleGround
void UpdateNodeWorldState(BG_AV_Nodes node);
/*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];
@ -388,7 +395,7 @@ class BattleGroundAV : public BattleGround
int32 m_Mine_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_RepTowerDestruction;

View file

@ -72,6 +72,28 @@ void BattleGroundEY::Update(uint32 diff)
else
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()
@ -85,7 +107,7 @@ void BattleGroundEY::StartingEventOpenDoors()
void BattleGroundEY::AddPoints(Team team, uint32 points)
{
BattleGroundTeamIndex team_index = GetTeamIndexByTeamId(team);
PvpTeamIndex team_index = GetTeamIndexByTeamId(team);
m_TeamScores[team_index] += points;
m_honorScoreTicks[team_index] += points;
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);
// spawn gameobjects
SpawnEvent(towerId, BG_TEAM_ALLIANCE, true);
SpawnEvent(towerId, TEAM_INDEX_ALLIANCE, true);
}
else if (team == HORDE)
{
@ -242,7 +264,7 @@ void BattleGroundEY::ProcessCaptureEvent(GameObject* go, uint32 towerId, Team te
SendMessageToAll(message, CHAT_MSG_BG_SYSTEM_HORDE);
// spawn gameobjects
SpawnEvent(towerId, BG_TEAM_HORDE, true);
SpawnEvent(towerId, TEAM_INDEX_HORDE, true);
}
else
{
@ -310,15 +332,15 @@ void BattleGroundEY::Reset()
// call parent's class reset
BattleGround::Reset();
m_TeamScores[BG_TEAM_ALLIANCE] = 0;
m_TeamScores[BG_TEAM_HORDE] = 0;
m_TeamScores[TEAM_INDEX_ALLIANCE] = 0;
m_TeamScores[TEAM_INDEX_HORDE] = 0;
m_towersAlliance = 0;
m_towersHorde = 0;
m_honorTicks = BattleGroundMgr::IsBGWeekend(GetTypeID()) ? EY_WEEKEND_HONOR_INTERVAL : EY_NORMAL_HONOR_INTERVAL;
m_honorScoreTicks[BG_TEAM_ALLIANCE] = 0;
m_honorScoreTicks[BG_TEAM_HORDE] = 0;
m_honorScoreTicks[TEAM_INDEX_ALLIANCE] = 0;
m_honorScoreTicks[TEAM_INDEX_HORDE] = 0;
m_flagState = EY_FLAG_STATE_ON_BASE;
m_flagCarrier.Clear();
@ -326,6 +348,7 @@ void BattleGroundEY::Reset()
m_flagRespawnTimer = 0;
m_resourceUpdateTimer = 0;
m_felReaverFlagTimer = 0;
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;
@ -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_HORDE, m_towersHorde);
FillInitialWorldState(data, count, WORLD_STATE_EY_RESOURCES_ALLIANCE, m_TeamScores[BG_TEAM_ALLIANCE]);
FillInitialWorldState(data, count, WORLD_STATE_EY_RESOURCES_HORDE, m_TeamScores[BG_TEAM_HORDE]);
FillInitialWorldState(data, count, WORLD_STATE_EY_RESOURCES_ALLIANCE, m_TeamScores[TEAM_INDEX_ALLIANCE]);
FillInitialWorldState(data, count, WORLD_STATE_EY_RESOURCES_HORDE, m_TeamScores[TEAM_INDEX_HORDE]);
// tower world states
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_RESOURCES_UPDATE_TIME (2 * IN_MILLISECONDS) //2 seconds
#define EY_FEL_REAVER_FLAG_UPDATE_TIME (1 * IN_MILLISECONDS) //1 second
enum EYWorldStates
{
@ -305,9 +306,10 @@ class BattleGroundEY : public BattleGround
ObjectGuid m_towers[EY_NODES_MAX];
uint32 m_honorTicks;
uint32 m_honorScoreTicks[BG_TEAMS_COUNT];
uint32 m_honorScoreTicks[PVP_TEAM_COUNT];
uint32 m_flagRespawnTimer;
uint32 m_resourceUpdateTimer;
uint32 m_felReaverFlagTimer;
};
#endif

View file

@ -59,7 +59,7 @@ INSTANTIATE_SINGLETON_1(BattleGroundMgr);
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)
{
@ -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
uint32 index = 0;
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)
++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)
{
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->GroupTeam == HORDE)
team_index = BG_TEAM_HORDE;
team_index = TEAM_INDEX_HORDE;
}
else
{
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
@ -287,16 +287,16 @@ void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* g
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->GroupTeam == HORDE)
team_index = BG_TEAM_HORDE;
team_index = TEAM_INDEX_HORDE;
}
else
{
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)
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();
// index to queue which group is current
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;
// the same thing for horde
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 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;
// 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
int32 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
int32 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
while (abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0))
int32 diffAli = aliFree - int32(m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount());
int32 diffHorde = hordeFree - int32(m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount());
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
if (diffAli < diffHorde)
{
// 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;
}
// 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)
break;
m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli);
m_SelectionPools[TEAM_INDEX_HORDE].KickGroup(diffHorde - diffAli);
}
}
else
{
// 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;
}
if (!m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
if (!m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount())
{
if (hordeFree <= diffAli + 1)
break;
m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
m_SelectionPools[TEAM_INDEX_ALLIANCE].KickGroup(diffAli - diffHorde);
}
}
// count diffs after small update
diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
diffAli = aliFree - int32(m_SelectionPools[TEAM_INDEX_ALLIANCE].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())
{
m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
m_SelectionPools[TEAM_INDEX_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
m_SelectionPools[TEAM_INDEX_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
// 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;
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)
{
@ -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
// 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);
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())
{
@ -653,8 +653,8 @@ bool BattleGroundQueue::CheckPremadeMatch(BattleGroundBracketId bracket_id, uint
// 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)
{
GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i)
GroupsQueueType::const_iterator itr_team[PVP_TEAM_COUNT];
for (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
{
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]))
@ -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
uint32 j = BG_TEAM_ALLIANCE;
if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
j = BG_TEAM_HORDE;
uint32 j = TEAM_INDEX_ALLIANCE;
if (m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() < m_SelectionPools[TEAM_INDEX_ALLIANCE].GetPlayerCount())
j = TEAM_INDEX_HORDE;
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
++(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]))
{
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;
}
// 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;
}
// 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 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
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;
BattleGroundTeamIndex teamIdx = BG_TEAM_ALLIANCE;
BattleGroundTeamIndex otherTeamIdx = BG_TEAM_HORDE;
PvpTeamIndex teamIdx = TEAM_INDEX_ALLIANCE;
PvpTeamIndex otherTeamIdx = TEAM_INDEX_HORDE;
Team otherTeamId = HORDE;
if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam)
if (m_SelectionPools[TEAM_INDEX_HORDE].GetPlayerCount() == minPlayersPerTeam)
{
teamIdx = BG_TEAM_HORDE;
otherTeamIdx = BG_TEAM_ALLIANCE;
teamIdx = TEAM_INDEX_HORDE;
otherTeamIdx = TEAM_INDEX_ALLIANCE;
otherTeamId = ALLIANCE;
}
// clear other team's selection
@ -782,16 +782,16 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
// and iterator is invalid
// clear selection pools
m_SelectionPools[BG_TEAM_ALLIANCE].Init();
m_SelectionPools[BG_TEAM_HORDE].Init();
m_SelectionPools[TEAM_INDEX_ALLIANCE].Init();
m_SelectionPools[TEAM_INDEX_HORDE].Init();
// call a function that does the job for us
FillPlayersToBG(bg, bracket_id);
// 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);
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);
if (!bg->HasFreeSlots())
@ -853,8 +853,8 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
}
}
m_SelectionPools[BG_TEAM_ALLIANCE].Init();
m_SelectionPools[BG_TEAM_HORDE].Init();
m_SelectionPools[TEAM_INDEX_ALLIANCE].Init();
m_SelectionPools[TEAM_INDEX_HORDE].Init();
if (bg_template->isBattleGround())
{
@ -869,14 +869,14 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
return;
}
// invite those selection pools
for (uint8 i = 0; i < BG_TEAMS_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 (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
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);
// start bg
bg2->StartBattleGround();
// clear structures
m_SelectionPools[BG_TEAM_ALLIANCE].Init();
m_SelectionPools[BG_TEAM_HORDE].Init();
m_SelectionPools[TEAM_INDEX_ALLIANCE].Init();
m_SelectionPools[TEAM_INDEX_HORDE].Init();
}
}
@ -896,8 +896,8 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
}
// invite those selection pools
for (uint8 i = 0; i < BG_TEAMS_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 (uint8 i = 0; i < PVP_TEAM_COUNT; ++i)
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);
// start bg
bg2->StartBattleGround();
@ -942,7 +942,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
// 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
@ -967,40 +967,40 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
// if we don't have, we must try to continue search in same queue
// tmp variables are correctly set
// 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[BG_TEAM_ALLIANCE];
for (; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE]))
itr_team[TEAM_INDEX_ALLIANCE] = itr_team[TEAM_INDEX_HORDE];
++itr_team[TEAM_INDEX_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
&& (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
|| (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime))
if (!(*itr_team[TEAM_INDEX_ALLIANCE])->IsInvitedToBGInstanceGUID
&& (((*itr_team[TEAM_INDEX_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[TEAM_INDEX_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
|| (*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;
}
}
}
// 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[BG_TEAM_HORDE];
for (; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE]))
itr_team[TEAM_INDEX_HORDE] = itr_team[TEAM_INDEX_ALLIANCE];
++itr_team[TEAM_INDEX_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
&& (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating)
|| (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime))
if (!(*itr_team[TEAM_INDEX_HORDE])->IsInvitedToBGInstanceGUID
&& (((*itr_team[TEAM_INDEX_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[TEAM_INDEX_HORDE])->ArenaTeamRating <= arenaMaxRating)
|| (*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;
}
}
}
// 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);
if (!arena)
@ -1009,28 +1009,28 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
return;
}
(*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating;
DEBUG_LOG("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating);
(*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating;
DEBUG_LOG("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating);
(*(itr_team[TEAM_INDEX_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[TEAM_INDEX_HORDE]))->ArenaTeamRating;
DEBUG_LOG("setting oposite teamrating for team %u to %u", (*(itr_team[TEAM_INDEX_ALLIANCE]))->ArenaTeamId, (*(itr_team[TEAM_INDEX_ALLIANCE]))->OpponentsTeamRating);
(*(itr_team[TEAM_INDEX_HORDE]))->OpponentsTeamRating = (*(itr_team[TEAM_INDEX_ALLIANCE]))->ArenaTeamRating;
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
if ((*(itr_team[BG_TEAM_ALLIANCE]))->GroupTeam != ALLIANCE)
if ((*(itr_team[TEAM_INDEX_ALLIANCE]))->GroupTeam != ALLIANCE)
{
// 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
m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[TEAM_INDEX_ALLIANCE]);
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_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
itr_team[BG_TEAM_HORDE] = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].begin();
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[TEAM_INDEX_HORDE]);
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[BG_TEAM_HORDE]), arena, HORDE);
InviteGroupToBG(*(itr_team[TEAM_INDEX_ALLIANCE]), arena, ALLIANCE);
InviteGroupToBG(*(itr_team[TEAM_INDEX_HORDE]), arena, HORDE);
DEBUG_LOG("Starting rated arena match!");

View file

@ -134,12 +134,12 @@ class BattleGroundQueue
};
// 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);
uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME];
uint32 m_WaitTimeLastPlayer[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS];
uint32 m_SumOfWaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS];
uint32 m_WaitTimes[PVP_TEAM_COUNT][MAX_BATTLEGROUND_BRACKETS][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME];
uint32 m_WaitTimeLastPlayer[PVP_TEAM_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 (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);
}
}
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);
}
}
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);
}
}
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);
}
}
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);
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);
else
{
@ -141,13 +141,13 @@ void BattleGroundWS::RespawnFlag(Team team, bool captured)
if (team == ALLIANCE)
{
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);
}
else
{
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);
}
@ -197,11 +197,11 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player* source)
return;
ClearHordeFlagCarrier(); // must be before aura remove to prevent 2 events (drop+capture) at the same time
// 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
source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
if (m_TeamScores[BG_TEAM_ALLIANCE] < BG_WS_MAX_TEAM_SCORE)
m_TeamScores[BG_TEAM_ALLIANCE] += 1;
if (m_TeamScores[TEAM_INDEX_ALLIANCE] < BG_WS_MAX_TEAM_SCORE)
m_TeamScores[TEAM_INDEX_ALLIANCE] += 1;
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE);
RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE);
}
@ -211,11 +211,11 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player* source)
return;
ClearAllianceFlagCarrier(); // must be before aura remove to prevent 2 events (drop+capture) at the same time
// 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
source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
if (m_TeamScores[BG_TEAM_HORDE] < BG_WS_MAX_TEAM_SCORE)
m_TeamScores[BG_TEAM_HORDE] += 1;
if (m_TeamScores[TEAM_INDEX_HORDE] < BG_WS_MAX_TEAM_SCORE)
m_TeamScores[TEAM_INDEX_HORDE] += 1;
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE);
RewardReputationToTeam(889, m_ReputationCapture, HORDE);
}
@ -237,9 +237,9 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player* source)
UpdatePlayerScore(source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures
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;
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;
if (winner)
@ -296,7 +296,7 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player* source)
{
ClearHordeFlagCarrier();
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);
set = true;
}
@ -309,7 +309,7 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player* source)
{
ClearAllianceFlagCarrier();
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);
set = true;
}
@ -354,7 +354,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player* source, GameObject* target
PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP);
SpawnEvent(WS_EVENT_FLAG_A, 0, false);
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
UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER);
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);
SpawnEvent(WS_EVENT_FLAG_H, 0, false);
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
UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER);
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);
SetAllianceFlagCarrier(source->GetObjectGuid());
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);
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);
SetHordeFlagCarrier(source->GetObjectGuid());
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);
UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1);
}
@ -478,9 +478,9 @@ void BattleGroundWS::UpdateFlagState(Team team, uint32 value)
void BattleGroundWS::UpdateTeamScore(Team team)
{
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
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)
@ -501,12 +501,12 @@ void BattleGroundWS::HandleAreaTrigger(Player* source, uint32 trigger)
case 3709: // Horde elixir of berserk spawn
break;
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())
EventPlayerCapturedFlag(source);
break;
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())
EventPlayerCapturedFlag(source);
break;
@ -532,7 +532,7 @@ void BattleGroundWS::Reset()
m_ActiveEvents[WS_EVENT_FLAG_A] = 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_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)
{
FillInitialWorldState(data, count, BG_WS_FLAG_CAPTURES_ALLIANCE, m_TeamScores[BG_TEAM_ALLIANCE]);
FillInitialWorldState(data, count, BG_WS_FLAG_CAPTURES_HORDE, m_TeamScores[BG_TEAM_HORDE]);
FillInitialWorldState(data, count, BG_WS_FLAG_CAPTURES_ALLIANCE, m_TeamScores[TEAM_INDEX_ALLIANCE]);
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);
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);
else
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);
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);
else
FillInitialWorldState(data, count, BG_WS_FLAG_UNK_HORDE, 0);
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);
else
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);
else
FillInitialWorldState(data, count, BG_WS_FLAG_STATE_ALLIANCE, 1);

View file

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

View file

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

View file

@ -6101,9 +6101,7 @@ bool ChatHandler::HandleGMFlyCommand(char* args)
if (!target)
target = m_session->GetPlayer();
WorldPacket data;
target->BuildMoveSetCanFlyPacket(&data, value, 0);
target->SendMessageToSet(&data, true);
target->SetCanFly(value);
PSendSysMessage(LANG_COMMAND_FLYMODE_STATUS, GetNameLink(target).c_str(), args);
return true;
}
@ -7310,6 +7308,64 @@ bool ChatHandler::HandleMmapTestArea(char* args)
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)
{
PSendSysMessage("Global raid instances reset, all players in raid instances will be teleported to homebind!");

View file

@ -1117,9 +1117,9 @@ bool ChatHandler::HandleDebugSpellCoefsCommand(char* args)
char const* dotDamageStr = GetMangosString(LANG_DOT_DAMAGE);
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,
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;
}

View file

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

View file

@ -37,16 +37,17 @@
template<class T>
void FleeingMovementGenerator<T>::_setTargetLocation(T& owner)
{
if (!&owner)
return;
// ignore in case other no reaction state
if (owner.hasUnitState((UNIT_STAT_CAN_NOT_REACT | UNIT_STAT_NOT_MOVE) & ~UNIT_STAT_FLEEING))
return;
float x, y, z;
if (!_getPoint(owner, x, y, z))
{
// random point not found recheck later
i_nextCheckTime.Reset(50);
return;
}
owner.addUnitState(UNIT_STAT_FLEEING_MOVE);
@ -55,7 +56,8 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T& owner)
path.calculate(x, y, z);
if (path.getPathType() & PATHFIND_NOPATH)
{
i_nextCheckTime.Reset(urand(1000, 1500));
// path not found recheck later
i_nextCheckTime.Reset(50);
return;
}
@ -69,9 +71,6 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T& owner)
template<class T>
bool FleeingMovementGenerator<T>::_getPoint(T& owner, float& x, float& y, float& z)
{
if (!&owner)
return false;
float dist_from_caster, angle_to_caster;
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);
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)
owner.GetMap()->GetHitPosition(curr_x, curr_y, curr_z, x, y, z, owner.GetPhaseMask(), -0.1f);
owner.UpdateAllowedPositionZ(x, y, z);
{
// check any collision
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;
}

View file

@ -509,6 +509,16 @@ void MotionMaster::MoveJump(float x, float y, float z, float horizontalSpeed, fl
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()
{
// 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 MoveDistract(uint32 timeLimit);
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 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.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
player.SetClientControl(&player, 1);
if (player.m_taxi.empty())
{

View file

@ -55,7 +55,7 @@ AggressorAI::MoveInLineOfSight(Unit* u)
return;
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);
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); }
Unit::AddToWorld();
// Make active if required
if (sWorld.isForceLoadMap(GetMapId()) || (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_ACTIVE))
SetActiveObjectState(true);
}
void Creature::RemoveFromWorld()
@ -384,7 +388,14 @@ bool Creature::InitEntry(uint32 Entry, CreatureData const* data /*=NULL*/, GameE
UpdateSpeed(MOVE_WALK, 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
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 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])
{
display_id = cinfo->ModelId[urand(0, 3)];
@ -1159,6 +1172,9 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
CreatureInfo const* cinfo = GetCreatureInfo();
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] &&
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);
}
// 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.
bool Creature::IsTappedBy(Player const* player) const
{
@ -2038,7 +2083,7 @@ bool Creature::IsOutOfThreatArea(Unit* pVictim) const
if (!pVictim->IsTargetableForAttack())
return true;
if (!pVictim->isInAccessablePlaceFor(this))
if (!pVictim->IsInAccessablePlaceFor(this))
return true;
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)
{
if (enable)

View file

@ -542,11 +542,11 @@ class Creature : public Unit
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
uint32 GetCorpseDelay() const { return m_corpseDelay; }
bool IsRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_CIVILIAN; }
bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_GUARD; }
bool IsCivilian() const { return (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_CIVILIAN) != 0; }
bool IsGuard() const { return (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_GUARD) != 0; }
bool CanWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
bool CanWalk() const { return (GetCreatureInfo()->InhabitType & INHABIT_GROUND) != 0; }
bool CanSwim() const { return (GetCreatureInfo()->InhabitType & INHABIT_WATER) != 0; }
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 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 IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectIndex index, bool castOnSelf) const override;
void SetLootStatus(CreatureLootStatus status);
bool IsTappedBy(Player const* player) const;
bool IsElite() const
@ -591,6 +592,10 @@ class Creature : public Unit
void SetWalk(bool enable, bool asDefault = true);
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 SetWaterWalk(bool enable) override;
@ -818,6 +823,7 @@ class Creature : public Unit
uint32 m_lootMoney;
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
CreatureLootStatus m_lootStatus; // loot status (used to know when we could loot, pickpocket or skin)
/// Timers
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_TARGET_MISSING_AURA:
case EVENT_T_RANGE:
case EVENT_T_ENERGY:
return true;
default:
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);
break;
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
pHolder.UpdateRepeatTimer(m_creature, event.range.repeatMin, event.range.repeatMax);
break;
@ -394,6 +402,9 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
break;
case EVENT_T_AURA:
{
if (!m_creature->IsInCombat())
return false;
SpellAuraHolder* holder = m_creature->GetSpellAuraHolder(event.buffed.spellId);
if (!holder || holder->GetStackAmount() < event.buffed.amount)
return false;
@ -419,6 +430,9 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
}
case EVENT_T_MISSING_AURA:
{
if (!m_creature->IsInCombat())
return false;
SpellAuraHolder* holder = m_creature->GetSpellAuraHolder(event.buffed.spellId);
if (holder && holder->GetStackAmount() >= event.buffed.amount)
return false;
@ -444,6 +458,21 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
}
case EVENT_T_RECEIVE_AI_EVENT:
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:
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;
@ -478,7 +507,7 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
if (count)
{
// select action number from found amount
uint32 idx = urand(0, count - 1);
uint32 idx = rnd % count;
// find selected action, skipping not used
uint32 j = 0;
@ -520,17 +549,17 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
if (action.type == ACTION_T_TEXT)
{
if (action.text.TextId[1] && action.text.TextId[2])
textId = action.text.TextId[urand(0, 2)];
else if (action.text.TextId[1] && urand(0, 1))
textId = action.text.TextId[rnd % 3];
else if (action.text.TextId[1] && (rnd % 2))
textId = action.text.TextId[1];
else
textId = action.text.TextId[0];
}
// 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])
textId = action.chanced_text.TextId[urand(0, 1)];
textId = action.chanced_text.TextId[rnd % 2];
else
textId = action.chanced_text.TextId[0];
}
@ -839,9 +868,9 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
Creature* pCreature = NULL;
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
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)
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_EventDiff = 0;
m_throwAIEventStep = 0;
// Reset all events to enabled
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)
{
// Reset all out of combat timers
case EVENT_T_TIMER_OOC:
{
if ((*i).UpdateRepeatTimer(m_creature, event.timer.initialMin, event.timer.initialMax))
(*i).Enabled = true;
if (i->UpdateRepeatTimer(m_creature, event.timer.initialMin, event.timer.initialMax))
i->Enabled = true;
break;
}
default:
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;
//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)
{
if ((*i).Event.event_type == EVENT_T_REACHED_HOME)
if (i->Event.event_type == EVENT_T_REACHED_HOME)
ProcessEvent(*i);
}
@ -1079,18 +1105,16 @@ void CreatureEventAI::EnterEvadeMode()
m_creature->DeleteThreatList();
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->SetLootRecipient(NULL);
if (m_bEmptyList)
return;
m_creature->SetLootRecipient(nullptr);
// Handle Evade events
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);
}
}
@ -1112,7 +1136,7 @@ void CreatureEventAI::JustDied(Unit* killer)
// Handle On Death events
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);
}
@ -1127,7 +1151,7 @@ void CreatureEventAI::KilledUnit(Unit* victim)
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);
}
}
@ -1136,7 +1160,7 @@ void CreatureEventAI::JustSummoned(Creature* pUnit)
{
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);
}
}
@ -1145,7 +1169,7 @@ void CreatureEventAI::SummonedCreatureJustDied(Creature* pUnit)
{
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);
}
}
@ -1154,12 +1178,12 @@ void CreatureEventAI::SummonedCreatureDespawn(Creature* pUnit)
{
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);
}
}
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);
@ -1176,22 +1200,22 @@ void CreatureEventAI::EnterCombat(Unit* enemy)
// Check for on combat start events
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)
{
case EVENT_T_AGGRO:
(*i).Enabled = true;
i->Enabled = true;
ProcessEvent(*i, enemy);
break;
// Reset all in combat timers
case EVENT_T_TIMER_IN_COMBAT:
if ((*i).UpdateRepeatTimer(m_creature, event.timer.initialMin, event.timer.initialMax))
(*i).Enabled = true;
if (i->UpdateRepeatTimer(m_creature, event.timer.initialMin, event.timer.initialMax))
i->Enabled = true;
break;
// All normal events need to be re-enabled and their time set to 0
default:
(*i).Enabled = true;
(*i).Time = 0;
i->Enabled = true;
i->Time = 0;
break;
}
}
@ -1221,21 +1245,21 @@ void CreatureEventAI::MoveInLineOfSight(Unit* who)
return;
// 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)
{
if ((*itr).Event.event_type == EVENT_T_OOC_LOS)
if (itr->Event.event_type == EVENT_T_OOC_LOS)
{
// can trigger if closer than fMaxAllowedRange
float fMaxAllowedRange = (float)(*itr).Event.ooc_los.maxRange;
float fMaxAllowedRange = (float)itr->Event.ooc_los.maxRange;
// if friendly event && who is not hostile OR hostile event && who is hostile
if ((itr->Event.ooc_los.noHostile && !m_creature->IsHostileTo(who)) ||
((!itr->Event.ooc_los.noHostile) && m_creature->IsHostileTo(who)))
{
// if range is ok and we are actually in LOS
if (m_creature->IsWithinDistInMap(who, fMaxAllowedRange) && m_creature->IsWithinLOSInMap(who))
{
// if friendly event&&who is not hostile OR hostile event&&who is hostile
if (((*itr).Event.ooc_los.noHostile && !m_creature->IsHostileTo(who)) ||
((!(*itr).Event.ooc_los.noHostile) && m_creature->IsHostileTo(who)))
ProcessEvent(*itr, who);
}
}
@ -1246,7 +1270,7 @@ void CreatureEventAI::MoveInLineOfSight(Unit* who)
return;
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)
return;
@ -1271,10 +1295,10 @@ void CreatureEventAI::MoveInLineOfSight(Unit* who)
void CreatureEventAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell)
{
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 (!(*i).Event.spell_hit.spellId || pSpell->Id == (*i).Event.spell_hit.spellId)
if (pSpell->SchoolMask & (*i).Event.spell_hit.schoolMask)
if (!i->Event.spell_hit.spellId || pSpell->Id == i->Event.spell_hit.spellId)
if (pSpell->SchoolMask & i->Event.spell_hit.schoolMask)
ProcessEvent(*i, pUnit);
}
@ -1292,66 +1316,53 @@ void CreatureEventAI::UpdateAI(const uint32 diff)
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{
// 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
if (!((*i).Event.event_inverse_phase_mask & (1 << m_Phase)))
(*i).Time -= m_EventDiff;
if (!(i->Event.event_inverse_phase_mask & (1 << m_Phase)))
i->Time -= m_EventDiff;
}
else
i->Time = 0;
}
// Skip processing of events that have time remaining
// Skip processing of events that have time remaining or are disabled
if (!(i->Enabled) || i->Time)
continue;
}
else (*i).Time = 0;
}
// Events that are updated every EVENT_UPDATE_TIME
switch ((*i).Event.event_type)
{
case EVENT_T_TIMER_OOC:
case EVENT_T_TIMER_GENERIC:
if (IsTimerBasedEvent(i->Event.event_type))
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;
m_EventUpdateTime = EVENT_UPDATE_TIME;
}
}
else
{
m_EventDiff += diff;
m_EventUpdateTime -= diff;
}
// Melee Auto-Attack (recheck m_creature->getVictim in case of combat state was changed while processing events)
if (Combat && m_MeleeEnabled && m_creature->getVictim())
// Melee Auto-Attack (getVictim might be nullptr as result of timer based events and actions)
if (Combat && m_creature->getVictim())
{
// 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
{
@ -1478,12 +1489,12 @@ void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
{
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)
return;
if (itr->Event.receive_emote.emoteId != text_emote)
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))
{
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_TIMER_GENERIC = 29, // InitialMin, InitialMax, RepeatMin, RepeatMax
EVENT_T_RECEIVE_AI_EVENT = 30, // AIEventType, Sender-Entry, unused, unused
EVENT_T_ENERGY = 31, // EnergyMax%, EnergyMin%, RepeatMin, RepeatMax
EVENT_T_END,
};
@ -467,6 +468,7 @@ struct CreatureEventAI_Event
// EVENT_T_MANA = 3
// EVENT_T_TARGET_HP = 12
// EVENT_T_TARGET_MANA = 18
// EVENT_T_ENERGY = 31
struct
{
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);
}
/// 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)
{
switch (targetType)
@ -327,6 +327,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
case EVENT_T_MANA:
case EVENT_T_TARGET_HP:
case EVENT_T_TARGET_MANA:
case EVENT_T_ENERGY:
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);

View file

@ -1269,8 +1269,11 @@ void GameObject::Use(Unit* user)
player->RewardPlayerAndGroupAtCast(this);
}
if (scriptReturnValue)
{ return; }
// activate script
if (!scriptReturnValue)
GetMap()->ScriptsStart(sGameObjectScripts, GetGUIDLow(), spellCaster, this);
else
return;
// cast this spell later if provided
spellId = info->goober.spellId;
@ -2382,6 +2385,23 @@ void GameObject::ForceGameObjectHealth(int32 diff, Unit* caster)
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()
{
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
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:
void SwitchDoorOrButton(bool activate, bool alternative = false);
void TickCapturePoint();

View file

@ -48,7 +48,7 @@ void GuardAI::MoveInLineOfSight(Unit* u)
if (!m_creature->getVictim() && u->IsTargetableForAttack() &&
(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);
if (m_creature->IsWithinDistInMap(u, attackRadius))

View file

@ -332,7 +332,7 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
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);
return false;

View file

@ -70,7 +70,9 @@ enum LootType
LOOT_FISHINGHOLE = 20, // 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

View file

@ -664,19 +664,37 @@ void Object::BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, UpdateMask* u
{
*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)
{
if (!target->isAllowedToLoot((Creature*)this))
*data << (m_uint32Values[index] & ~(UNIT_DYNFLAG_LOOTABLE | UNIT_DYNFLAG_TAPPED_BY_PLAYER));
else
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))
{
// flag only for original loot recipent
if (target->GetObjectGuid() == ((Creature*)this)->GetLootRecipientGuid())
*data << m_uint32Values[index];
else
*data << (m_uint32Values[index] & ~(UNIT_DYNFLAG_TAPPED | UNIT_DYNFLAG_TAPPED_BY_PLAYER));
/* 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 (send_value & UNIT_DYNFLAG_LOOTABLE)
{ send_value = send_value & ~UNIT_DYNFLAG_LOOTABLE; }
/* If we are allowed to loot it and mob is tapped by us, destroy the tapped flag */
bool is_tapped = target->IsTappedByMeOrMyGroup((Creature*)this);
/* If the creature has tapped flag but is tapped by us, remove the flag */
if (send_value & UNIT_DYNFLAG_TAPPED && is_tapped)
{ send_value = send_value & ~UNIT_DYNFLAG_TAPPED; }
*data << send_value;
}
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
}
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())
{
case TYPEID_UNIT:
@ -1492,21 +1513,21 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z) const
bool canSwim = ((Creature const*)this)->CanSwim();
float ground_z = z;
float max_z = canSwim
? GetTerrain()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK))
: ((ground_z = GetMap()->GetHeight(GetPhaseMask(), x, y, z)));
? atMap->GetTerrain()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK))
: ((ground_z = atMap->GetHeight(GetPhaseMask(), x, y, z)));
if (max_z > INVALID_HEIGHT)
{
if (z > max_z)
{ z = max_z; }
z = max_z;
else if (z < ground_z)
{ z = ground_z; }
z = ground_z;
}
}
else
{
float ground_z = GetMap()->GetHeight(GetPhaseMask(), x, y, z);
float ground_z = atMap->GetHeight(GetPhaseMask(), x, y, z);
if (z < ground_z)
{ z = ground_z; }
z = ground_z;
}
break;
}
@ -1516,18 +1537,18 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z) const
if (!((Player const*)this)->CanFly())
{
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 (z > max_z)
{ z = max_z; }
z = max_z;
else if (z < ground_z)
{ z = ground_z; }
z = ground_z;
}
}
else
{
float ground_z = GetMap()->GetHeight(GetPhaseMask(), x, y, z);
float ground_z = atMap->GetHeight(GetPhaseMask(), x, y, z);
if (z < ground_z)
z = ground_z;
}
@ -1535,9 +1556,9 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z) const
}
default:
{
float ground_z = GetMap()->GetHeight(GetPhaseMask(), x, y, z);
float ground_z = atMap->GetHeight(GetPhaseMask(), x, y, z);
if (ground_z > INVALID_HEIGHT)
{ z = ground_z; }
z = ground_z;
break;
}
}
@ -1914,9 +1935,9 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
if (!sWorld.getConfig(CONFIG_BOOL_DETECT_POS_COLLISION))
{
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
{ UpdateGroundPositionZ(x, y, z); }
UpdateGroundPositionZ(x, y, z);
return;
}
@ -1942,12 +1963,12 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
if (selector.CheckOriginalAngle())
{
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
{ UpdateGroundPositionZ(x, y, z); }
UpdateGroundPositionZ(x, y, z);
if (fabs(init_z - z) < dist && IsWithinLOS(x, y, z))
{ return; }
return;
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();
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
{ UpdateGroundPositionZ(x, y, z); }
UpdateGroundPositionZ(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)
@ -1980,9 +2001,9 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
y = first_y;
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
{ UpdateGroundPositionZ(x, y, z); }
UpdateGroundPositionZ(x, y, z);
return;
}
@ -1996,12 +2017,12 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
z = GetPositionZ();
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
{ UpdateGroundPositionZ(x, y, z); }
UpdateGroundPositionZ(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 :(
@ -2009,9 +2030,9 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
y = first_y;
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
{ UpdateGroundPositionZ(x, y, z); }
UpdateGroundPositionZ(x, y, z);
}
void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update)

View file

@ -536,7 +536,7 @@ class WorldObject : public Object
bool IsPositionValid() 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;

View file

@ -1438,7 +1438,7 @@ void ObjectMgr::LoadCreatures()
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;
}
@ -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
{
AddCreatureToGrid(guid, &data);
if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_ACTIVE)
m_activeCreatures.insert(ActiveCreatureGuidsOnMap::value_type(data.mapid, guid));
}
++count;
}
while (result->NextRow());
@ -7580,9 +7585,9 @@ void ObjectMgr::LoadCreatureQuestRelations()
{
CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
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))
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
std::set<uint32> trainer_ids;
bool hasErrored = false;
for (CacheTrainerSpellMap::const_iterator tItr = m_mCacheTrainerTemplateSpellMap.begin(); tItr != m_mCacheTrainerTemplateSpellMap.end(); ++tItr)
trainer_ids.insert(tItr->first);
@ -9407,19 +9413,22 @@ void ObjectMgr::LoadTrainerTemplates()
for (uint32 i = 1; i < sCreatureStorage.GetMaxEntry(); ++i)
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{
if (cInfo->TrainerTemplateId)
{
if (m_mCacheTrainerTemplateSpellMap.find(cInfo->TrainerTemplateId) != m_mCacheTrainerTemplateSpellMap.end())
trainer_ids.erase(cInfo->TrainerTemplateId);
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)
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)
@ -9497,7 +9506,7 @@ void ObjectMgr::LoadVendorTemplates()
if (m_mCacheVendorTemplateItemMap.find(cInfo->VendorTemplateId) != m_mCacheVendorTemplateItemMap.end())
vendor_ids.erase(cInfo->VendorTemplateId);
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);
}
/* 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()
{
m_mCacheNpcTextIdMap.clear();
@ -9568,11 +9627,9 @@ void ObjectMgr::LoadGossipMenu(std::set<uint32>& gossipScriptSet)
if (!result)
{
BarGoLink bar(1);
bar.step();
sLog.outString();
sLog.outErrorDb(">> Loaded gossip_menu, table is empty!");
sLog.outString();
return;
}
@ -9631,20 +9688,25 @@ void ObjectMgr::LoadGossipMenu(std::set<uint32>& gossipScriptSet)
delete result;
sLog.outString();
sLog.outString(">> Loaded %u gossip_menu entries", count);
// post loading tests
for (uint32 i = 1; i < sCreatureStorage.GetMaxEntry(); ++i)
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
if (cInfo->GossipMenuId)
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);
}
if (!sLog.HasLogFilter(LOG_FILTER_DB_STRICTED_CHECK))
{
for (SQLStorageBase::SQLSIterator<GameObjectInfo> itr = sGOStorage.getDataBegin<GameObjectInfo>(); itr < sGOStorage.getDataEnd<GameObjectInfo>(); ++itr)
if (uint32 menuid = itr->GetGossipMenuId())
if (m_mGossipMenusMap.find(menuid) == m_mGossipMenusMap.end())
ERROR_DB_STRICT_LOG("Gameobject (Entry: %u) has gossip_menu_id = %u for nonexistent menu", itr->id, menuid);
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)
@ -9660,11 +9722,9 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
if (!result)
{
BarGoLink bar(1);
bar.step();
sLog.outString();
sLog.outErrorDb(">> Loaded gossip_menu_option, table is empty!");
sLog.outString();
return;
}
@ -9770,7 +9830,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
}
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))
@ -9804,7 +9864,6 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
m_mGossipMenuItemsMap.insert(GossipMenuItemsMap::value_type(gMenuItem.menu_id, gMenuItem));
++count;
}
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.outString();
sLog.outString(">> Loaded %u gossip_menu_option entries", count);
sLog.outString();
}
void ObjectMgr::LoadGossipMenus()

View file

@ -831,6 +831,9 @@ class ObjectMgr
void LoadTrainerTemplates();
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();
std::string GeneratePetName(uint32 entry);
@ -1340,10 +1343,13 @@ class ObjectMgr
HalfNameMap PetHalfName0;
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)
CreatureClassLvlStats m_creatureClassLvlStats[DEFAULT_MAX_CREATURE_LEVEL + 1][MAX_CREATURE_CLASS][MAX_EXPANSION + 1];
MapObjectGuids mMapObjectGuids;
ActiveCreatureGuidsOnMap m_activeCreatures;
CreatureDataMap mCreatureDataMap;
CreatureLocaleMap mCreatureLocaleMap;
GameObjectDataMap mGameObjectDataMap;

View file

@ -504,6 +504,7 @@ void Pet::SetDeathState(DeathState s) // overwrite virtual
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
CastPetAuras(true);
}
CastOwnerTalentAuras();
}
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)
{
if (apply)

View file

@ -206,6 +206,7 @@ class Pet : public Creature
bool CanTakeMoreActiveSpells(uint32 SpellIconID);
void ToggleAutocast(uint32 spellid, bool apply);
void SetModeFlags(PetModeFlags mode);
void ApplyModeFlags(PetModeFlags mode, bool apply);
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);
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;
AutoSpellList m_autospells;

View file

@ -60,7 +60,7 @@ void PetAI::MoveInLineOfSight(Unit* u)
return;
if (u->IsTargetableForAttack() && m_creature->IsHostileTo(u) &&
u->isInAccessablePlaceFor(m_creature))
u->IsInAccessablePlaceFor(m_creature))
{
float attackRadius = m_creature->GetAttackDistance(u);
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)
return;
if (money > m_player->GetMoney())
{
m_player->GetSession()->SendTradeStatus(TRADE_STATUS_CLOSE_WINDOW);
return;
}
m_money = money;
SetAccepted(false);
@ -1264,19 +1270,17 @@ void Player::Update(uint32 update_diff, uint32 p_time)
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
}
}
}
}// Speed collect rest bonus (section/in hour)
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
{
float bubble = 0.125f * sWorld.getConfig(CONFIG_FLOAT_RATE_REST_INGAME);
// Speed collect rest bonus (section/in hour)
SetRestBonus(float(GetRestBonus() + time_inn * (GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 72000) * bubble));
UpdateInnerTime(time(NULL));
SetRestBonus(GetRestBonus() + ComputeRest(time_inn));
UpdateInnerTime(now);
}
}
}
@ -2888,7 +2892,7 @@ void Player::InitStatsForLevel(bool reapplyMods)
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
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
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)
{
if (m_items[i] == NULL)
if (m_items[i] == nullptr)
continue;
m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
}
for (int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
{
if (m_items[i] == NULL)
if (m_items[i] == nullptr)
continue;
m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
@ -4555,6 +4559,38 @@ void Player::SetWaterWalk(bool enable)
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:
- a resurrectable corpse must not be loaded for the player (only bones)
- 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
if (GetGroup() && (old_x != x || old_y != y))
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
@ -6966,13 +6999,13 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
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())
SetFFAPvP(false);
}
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
@ -7483,9 +7516,9 @@ void Player::ApplyItemEquipSpell(Item* item, bool apply, bool form_change)
else
{
// 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
if (spellData.SpellTrigger == ITEM_SPELLTRIGGER_ON_USE && spellData.SpellCharges < 0)
if (spellData.SpellTrigger == ITEM_SPELLTRIGGER_ON_USE && (form_change || spellData.SpellCharges < 0))
continue;
}
@ -14004,6 +14037,10 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const
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() != qInfo->GetPrevQuestId())
return true;
// can be start if only all quests in prev quest exclusive group completed and rewarded
ExclusiveQuestGroupsMapBounds bounds = sObjectMgr.GetExclusiveQuestGroupsMapBounds(qPrevInfo->GetExclusiveGroup());
@ -14037,6 +14074,11 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const
if (qPrevInfo->GetExclusiveGroup() >= 0)
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)
// can be start if only all quests in prev quest exclusive group active
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
// join player to battleground group
currentBg->EventPlayerLoggedIn(this, GetObjectGuid());
currentBg->EventPlayerLoggedIn(this);
currentBg->AddOrSetPlayerToCorrectBgGroup(this, GetObjectGuid(), m_bgData.bgTeam);
SetInviteForBattleGroundQueueType(bgQueueTypeId, currentBg->GetInstanceID());
@ -15722,17 +15764,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
m_rest_bonus = fields[21].GetFloat();
if (time_diff > 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);
}
SetRestBonus(GetRestBonus() + ComputeRest(time_diff, true, (fields[23].GetInt32() > 0)));
// load skills after InitStatsForLevel because it triggering aura apply also
_LoadSkills(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSKILLS));
@ -15933,6 +15965,43 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder)
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)
{
// never tapped by any (mob solo kill)
@ -21716,6 +21785,123 @@ void Player::SetTitle(CharTitlesEntry const* title, bool lost)
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)
{
SetCurrentRune(index, newType);
@ -21749,7 +21935,7 @@ void Player::ResyncRunes()
for (uint32 i = 0; i < MAX_RUNES; ++i)
{
data << uint8(GetCurrentRune(i)); // rune type
data << uint8(255 - (GetRuneCooldown(i) * 51)); // passed cooldown time (0-255)
data << uint8(GetRuneCooldownFraction(i));
}
GetSession()->SendPacket(&data);
}
@ -21761,16 +21947,6 @@ void Player::AddRunePower(uint8 index)
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()
{
if (getClass() != CLASS_DEATH_KNIGHT)
@ -24066,6 +24242,77 @@ bool Player::FitArmorSpecializationRules(SpellEntry const * spellProto) const
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)
{
WorldPacket data(SMSG_PETITION_SIGN_RESULTS, 8 + 8 + 4);

View file

@ -353,7 +353,12 @@ struct Areas
};
#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
{
@ -364,17 +369,30 @@ enum RuneType
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
{
uint8 BaseRune;
uint8 CurrentRune;
uint16 BaseCooldown;
uint16 Cooldown; // msec
Aura const* ConvertAura;
};
struct Runes
{
RuneInfo runes[MAX_RUNES];
uint8 runeState; // mask of available runes
uint32 lastUsedRuneMask;
void SetRuneState(uint8 index, bool set = true)
{
@ -1191,6 +1209,15 @@ class Player : public Unit
}
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
{
return rest_type;
@ -1539,6 +1566,9 @@ class Player : public Unit
void AddTimedQuest(uint32 quest_id) { m_timedquests.insert(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 ***/
/*********************************************************/
@ -2058,6 +2088,10 @@ class Player : public Unit
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 SetWaterWalk(bool enable) override;
@ -2371,6 +2405,7 @@ class Player : public Unit
bool isMoving() const { return m_movementInfo.HasMovementFlag(movementFlagsMask); }
bool isMovingOrTurning() const { return m_movementInfo.HasMovementFlag(movementOrTurningFlagsMask); }
bool CanSwim() const { return true; }
bool CanFly() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_CAN_FLY); }
bool IsFlying() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_FLYING); }
bool IsFreeFlying() const { return HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED) || HasAuraType(SPELL_AURA_FLY); }
@ -2499,6 +2534,7 @@ class Player : public Unit
GridReference<Player>& GetGridRef() { return m_gridRef; }
MapReference& GetMapRef() { return m_mapRef; }
bool IsTappedByMeOrMyGroup(Creature* creature);
bool isAllowedToLoot(Creature* creature);
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 GetCurrentRune(uint8 index) const { return RuneType(m_runes->runes[index].CurrentRune); }
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;
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 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 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);
bool ActivateRunes(RuneType type, uint32 count);
void ResyncRunes();

View file

@ -811,6 +811,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
case 13139: // net-o-matic special effect
case 23445: // evil twin
case 35679: // Protectorate Demolitionist
case 37695: // Stanky
case 38637: // Nether Exhaustion (red)
case 38638: // Nether Exhaustion (green)
case 38639: // Nether Exhaustion (blue)
@ -843,6 +844,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
return false;
break;
case SPELL_AURA_MOD_DAMAGE_TAKEN: // dependent from bas point sign (positive -> negative)
case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
if (spellEffect->CalculateSimpleValue() < 0)
return true;
// let check by target modes (for Amplify Magic cases/etc)
@ -1407,7 +1409,7 @@ struct DoSpellProcEvent
++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(); }
SpellProcEventMap& spe_map;
SpellProcEventMap::const_iterator state;
@ -1694,7 +1696,7 @@ void SpellMgr::LoadSpellBonuses()
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);
}
@ -1716,7 +1718,7 @@ void SpellMgr::LoadSpellBonuses()
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);
}
@ -2874,7 +2876,7 @@ SpellEntry const* SpellMgr::SelectAuraRankForLevel(SpellEntry const* spellInfo,
break;
// if found appropriate level
if (level + 10 >= spellInfo->GetSpellLevel())
if (level + 10 >= nextSpellInfo->GetSpellLevel())
return nextSpellInfo;
// one rank less then
@ -3562,7 +3564,7 @@ void SpellMgr::LoadSpellScriptTarget()
{
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);
continue;
}

View file

@ -976,8 +976,8 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
{
SpellEntry const* shareSpell = (*itr)->GetSpellProto();
uint32 shareDamage = uint32(damage*(*itr)->GetModifier()->m_amount / 100.0f);
DealDamageMods(shareTarget, shareDamage, NULL);
DealDamage(shareTarget, shareDamage, 0, damagetype, GetSpellSchoolMask(shareSpell), shareSpell, false);
DealDamageMods(shareTarget, shareDamage, nullptr);
DealDamage(shareTarget, shareDamage, nullptr, damagetype, GetSpellSchoolMask(shareSpell), shareSpell, false);
}
}
}
@ -1681,9 +1681,11 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage* damageInfo, int32 damage, S
{ return; }
if (!this || !pVictim)
{ return; }
if (!this->IsAlive() || !pVictim->IsAlive())
{ return; }
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
bool crit = IsSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType);
@ -3521,7 +3523,7 @@ SpellMissInfo Unit::SpellHitResult(Unit* pVictim, SpellEntry const* spell, bool
return SPELL_MISS_EVADE;
// 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;
// All positive spells can`t miss
@ -3530,7 +3532,7 @@ SpellMissInfo Unit::SpellHitResult(Unit* pVictim, SpellEntry const* spell, bool
return SPELL_MISS_NONE;
// Check for immune
if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell)))
if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell)) && !spell->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY))
return SPELL_MISS_IMMUNE;
// Try victim reflect spell
@ -4027,7 +4029,7 @@ void Unit::SetFacingToObject(WorldObject* pObject)
SetFacingTo(GetAngle(pObject));
}
bool Unit::isInAccessablePlaceFor(Creature const* c) const
bool Unit::IsInAccessablePlaceFor(Creature const* c) const
{
if (IsInWater())
return c->CanSwim();
@ -5875,7 +5877,7 @@ bool Unit::IsHostileTo(Unit const* unit) const
return false;
// 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;
// PvP FFA state
@ -5987,7 +5989,7 @@ bool Unit::IsFriendlyTo(Unit const* unit) const
return true;
// 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;
// PvP FFA state
@ -6661,6 +6663,17 @@ void Unit::EnergizeBySpell(Unit* pVictim, uint32 SpellID, uint32 Damage, Powers
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)
{
// 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));
// 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;
@ -7568,7 +7581,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* pVictim, SpellEntry const* spellProto,
int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(GetSpellSchoolMask(spellProto));
// 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
float heal = (healamount + DoneTotal * int32(stack)) * DoneTotalMod;
@ -7612,7 +7625,7 @@ uint32 Unit::SpellHealingBonusTaken(Unit* pCaster, SpellEntry const* spellProto,
int32 TakenAdvertisedBenefit = SpellBaseHealingBonusTaken(GetSpellSchoolMask(spellProto));
// 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);
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)
{
// 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;
@ -8257,6 +8270,10 @@ void Unit::Mount(uint32 mount, uint32 spellId)
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 (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
{ ((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)
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
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
if (invisible && (
@ -8705,35 +8745,18 @@ bool Unit::IsVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo
// special cases for always overwrite invisibility/stealth
if (invisible || m_Visibility == VISIBILITY_GROUP_STEALTH)
{
// non-hostile case
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
if (u->IsHostileTo(this))
{
// Hunter mark functionality
AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED);
for (AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
if ((*iter)->GetCasterGuid() == u->GetObjectGuid())
return true;
// else apply detecting check for stealth
}
// none other cases for detect invisibility, so invisible
if (invisible)
return false;
// else apply stealth detecting check
}
// 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)
{
if ((caster = (*aura)->GetCaster()) && caster->IsInMap(this) &&
caster->IsTargetableForAttack() && caster->isInAccessablePlaceFor((Creature*)this) &&
caster->IsTargetableForAttack() && caster->IsInAccessablePlaceFor((Creature*)this) &&
!IsSecondChoiceTarget(caster, true))
{
target = caster;
@ -9581,7 +9604,7 @@ bool Unit::SelectHostileTarget()
{
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;
}
}
@ -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_BLOCK_DAMAGE_PERCENT 30
#define SCALE_SPELLPOWER_HEALING 1.88f
/**
* byte value (UNIT_FIELD_BYTES_1,0).
*
@ -225,9 +227,9 @@ enum UnitPVPStateFlags
UNIT_BYTE2_FLAG_PVP = 0x01,
UNIT_BYTE2_FLAG_UNK1 = 0x02,
UNIT_BYTE2_FLAG_FFA_PVP = 0x04,
UNIT_BYTE2_FLAG_SANCTUARY = 0x08,
UNIT_BYTE2_FLAG_UNK4 = 0x10,
UNIT_BYTE2_FLAG_UNK5 = 0x20,
UNIT_BYTE2_FLAG_SUPPORTABLE = 0x08, // allows for being targeted for healing/bandaging by friendlies
UNIT_BYTE2_FLAG_AURAS = 0x10, // show possitive auras as positive, and allow its dispel
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_UNK7 = 0x80
};
@ -596,7 +598,7 @@ enum UnitFlags
UNIT_FLAG_PVP = 0x00001000, // changed in 3.0.3
UNIT_FLAG_SILENCED = 0x00002000, // silenced, 2.1.1
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_PACIFIED = 0x00020000, // 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 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 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 IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEFLAG_WALK_MODE); }
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*/) {}
/**
* 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
void UpdateModelData();
void SendCollisionHeightUpdate(float height);
DynamicObject* GetDynObject(uint32 spellId, SpellEffectIndex effIndex);
DynamicObject* GetDynObject(uint32 spellId);
@ -3485,6 +3494,9 @@ class Unit : public WorldObject
bool IsLinkingEventTrigger() const { return m_isCreatureLinkingTrigger; }
virtual bool CanSwim() const = 0;
virtual bool CanFly() const = 0;
bool IsSplineEnabled() const;
bool IsInWorgenForm(bool inPermanent = false) const;
@ -3496,6 +3508,8 @@ class Unit : public WorldObject
void BuildSendPlayVisualPacket(WorldPacket* data, uint32 value, bool impact);
void BuildMoveSetCanFlyPacket(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:
explicit Unit();

View file

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

View file

@ -86,7 +86,8 @@ DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequences
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt);
DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt);
DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore(CreatureModelDatafmt);
DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt); // sCreatureModelDataStore
DBCStorage <CreatureTypeEntry> sCreatureTypeStore(CreatureTypefmt);
DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore(CurrencyTypesfmt);
@ -516,6 +517,7 @@ void LoadDBCStores(const std::string& dataPath)
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,sCreatureFamilyStore, dbcPath,"CreatureFamily.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureModelDataStore, dbcPath,"CreatureModelData.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureSpellDataStore, dbcPath,"CreatureSpellData.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureTypeStore, dbcPath,"CreatureType.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCurrencyTypesStore, dbcPath,"CurrencyTypes.dbc");
@ -1004,34 +1006,15 @@ uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
return mapid;
}
ContentLevels GetContentLevelsForMapAndZone(uint32 mapId, uint32 zoneId)
ContentLevels GetContentLevelsForMap(uint32 mapid)
{
MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
if (!mapEntry)
return CONTENT_1_60;
if (mapEntry->rootPhaseMap != -1)
mapId = mapEntry->rootPhaseMap;
switch (mapId)
{
case 648: // Lost Islands
case 654: // Gilneas
// exceptions for 648 - Goblin Starter area and 654 - Worgen Starter area
if (mapid == 648 || mapid == 654)
return CONTENT_1_60;
default:
break;
}
switch (zoneId)
{
case 616: // Mount Hyjal
case 4922: // Twilight Highlands
case 5034: // Uldum
case 5042: // Deepholm
return CONTENT_81_85;
default:
break;
}
switch (mapEntry->Expansion())
{
@ -1051,50 +1034,9 @@ ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id)
if (ch && ch->ChannelID == channel_id)
return ch;
}
return NULL;
return nullptr;
}
/*
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)
@ -1145,6 +1087,44 @@ bool Map2ZoneCoordinates(float& x, float& y, uint32 zone)
return true;
}
ContentLevels GetContentLevelsForMapAndZone(uint32 mapId, uint32 zoneId)
{
MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
if (!mapEntry)
return CONTENT_1_60;
if (mapEntry->rootPhaseMap != -1)
mapId = mapEntry->rootPhaseMap;
switch (mapId)
{
case 648: // Lost Islands
case 654: // Gilneas
return CONTENT_1_60;
default:
break;
}
switch (zoneId)
{
case 616: // Mount Hyjal
case 4922: // Twilight Highlands
case 5034: // Uldum
case 5042: // Deepholm
return CONTENT_81_85;
default:
break;
}
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;
}
}
MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty 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 <CreatureDisplayInfoExtraEntry>sCreatureDisplayInfoExtraStore;
extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore;
extern DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore;
extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore;
extern DBCStorage <CreatureTypeEntry> sCreatureTypeStore;
extern DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore;

View file

@ -751,7 +751,7 @@ struct CinematicSequencesEntry
struct CreatureDisplayInfoEntry
{
uint32 Displayid; // 0 m_ID
// 1 m_modelID
uint32 ModelId; // 1 m_modelID
// 2 m_soundID
uint32 ExtendedDisplayInfoID; // 3 m_extendedDisplayInfoID -> CreatureDisplayInfoExtraEntry::DisplayExtraId
float Scale; // 4 m_creatureModelScale
@ -797,6 +797,28 @@ struct CreatureFamilyEntry
// 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
struct CreatureSpellDataEntry
@ -861,7 +883,7 @@ struct DestructibleModelDataEntry
// uint32 unk17; // 17
// uint32 unk18; // 18
// uint32 unk19; // 19
//uint32 smokeDisplayId; // 20
uint32 smokeDisplayId; // 20
// uint32 unk21; // 21
// uint32 unk22; // 22
// uint32 unk23; // 23
@ -1380,7 +1402,6 @@ struct MapEntry
MapID == 509 || MapID == 534 || MapID == 560 || // AhnQiraj, HyjalPast, HillsbradPast
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 == 631 || MapID == 658 || MapID == 724 || // Icecrown Citadel, Pit of Saron, Ruby Sanctum
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
@ -1724,36 +1745,45 @@ struct ClassFamilyMask
struct SpellAuraOptionsEntry
{
//uint32 Id; // 0 m_ID
uint32 StackAmount; // 51 m_cumulativeAura
uint32 procChance; // 38 m_procChance
uint32 procCharges; // 39 m_procCharges
uint32 procFlags; // 37 m_procTypeMask
uint32 StackAmount; // 1 m_cumulativeAura
uint32 procChance; // 2 m_procChance
uint32 procCharges; // 3 m_procCharges
uint32 procFlags; // 4 m_procTypeMask
};
// SpellAuraRestrictions.dbc
struct SpellAuraRestrictionsEntry
{
//uint32 Id; // 0 m_ID
uint32 CasterAuraState; // 21 m_casterAuraState
uint32 TargetAuraState; // 22 m_targetAuraState
uint32 CasterAuraStateNot; // 23 m_excludeCasterAuraState
uint32 TargetAuraStateNot; // 24 m_excludeTargetAuraState
uint32 casterAuraSpell; // 25 m_casterAuraSpell
uint32 targetAuraSpell; // 26 m_targetAuraSpell
uint32 excludeCasterAuraSpell; // 27 m_excludeCasterAuraSpell
uint32 excludeTargetAuraSpell; // 28 m_excludeTargetAuraSpell
uint32 CasterAuraState; // 1 m_casterAuraState
uint32 TargetAuraState; // 2 m_targetAuraState
uint32 CasterAuraStateNot; // 3 m_excludeCasterAuraState
uint32 TargetAuraStateNot; // 4 m_excludeTargetAuraState
uint32 casterAuraSpell; // 5 m_casterAuraSpell
uint32 targetAuraSpell; // 6 m_targetAuraSpell
uint32 excludeCasterAuraSpell; // 7 m_excludeCasterAuraSpell
uint32 excludeTargetAuraSpell; // 8 m_excludeTargetAuraSpell
};
// SpellCastingRequirements.dbc
struct SpellCastingRequirementsEntry
{
//uint32 Id; // 0 m_ID
uint32 FacingCasterFlags; // 20 m_facingCasterFlags
//uint32 MinFactionId; // 159 m_minFactionID not used
//uint32 MinReputation; // 160 m_minReputation not used
int32 AreaGroupId; // 164 m_requiredAreaGroupId
//uint32 RequiredAuraVision; // 161 m_requiredAuraVision not used
uint32 RequiresSpellFocus; // 19 m_requiresSpellFocus
uint32 FacingCasterFlags; // 1 m_facingCasterFlags
//uint32 MinFactionId; // 2 m_minFactionID not used
//uint32 MinReputation; // 3 m_minReputation not used
int32 AreaGroupId; // 4 m_requiredAreaGroupId
//uint32 RequiredAuraVision; // 5 m_requiredAuraVision not used
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
@ -1761,22 +1791,21 @@ struct SpellCategoriesEntry
{
//uint32 Id; // 0 m_ID
uint32 Category; // 1 m_category
uint32 DmgClass; // 153 m_defenseType
uint32 Dispel; // 2 m_dispelType
uint32 Mechanic; // 3 m_mechanic
uint32 PreventionType; // 154 m_preventionType
uint32 StartRecoveryCategory; // 145 m_startRecoveryCategory
uint32 DmgClass; // 2 m_defenseType
uint32 Dispel; // 3 m_dispelType
uint32 Mechanic; // 4 m_mechanic
uint32 PreventionType; // 5 m_preventionType
uint32 StartRecoveryCategory; // 6 m_startRecoveryCategory
};
// SpellClassOptions.dbc
struct SpellClassOptionsEntry
{
//uint32 Id; // 0 m_ID
//uint32 modalNextSpell; // 50 m_modalNextSpell not used
ClassFamilyMask SpellFamilyFlags; // 149-151 m_spellClassMask NOTE: size is 12 bytes!!!
uint32 SpellFamilyName; // 148 m_spellClassSet
//uint32 modalNextSpell; // 1 m_modalNextSpell not used
ClassFamilyMask SpellFamilyFlags; // 2-4 m_spellClassMask NOTE: size is 12 bytes!!!
uint32 SpellFamilyName; // 5 m_spellClassSet
//char* Description; // 6 4.0.0
// helpers
bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const
@ -1809,9 +1838,9 @@ struct SpellClassOptionsEntry
struct SpellCooldownsEntry
{
//uint32 Id; // 0 m_ID
uint32 CategoryRecoveryTime; // 31 m_categoryRecoveryTime
uint32 RecoveryTime; // 30 m_recoveryTime
uint32 StartRecoveryTime; // 146 m_startRecoveryTime
uint32 CategoryRecoveryTime; // 1 m_categoryRecoveryTime
uint32 RecoveryTime; // 2 m_recoveryTime
uint32 StartRecoveryTime; // 3 m_startRecoveryTime
};
// SpellEffect.dbc
@ -1842,6 +1871,7 @@ struct SpellEffectEntry
uint32 EffectSpellId; // 24 m_spellId - spell.dbc
uint32 EffectIndex; // 25 m_spellEffectIdx
//uint32 unk; // 26 4.2.0 only 0 or 1
// helpers
int32 CalculateSimpleValue() const { return EffectBasePoints; }
@ -1859,29 +1889,68 @@ struct SpellEffectEntry
struct SpellEquippedItemsEntry
{
//uint32 Id; // 0 m_ID
int32 EquippedItemClass; // 70 m_equippedItemClass (value)
int32 EquippedItemInventoryTypeMask; // 72 m_equippedItemInvTypes (mask)
int32 EquippedItemSubClassMask; // 71 m_equippedItemSubclass (mask)
int32 EquippedItemClass; // 1 m_equippedItemClass (value)
int32 EquippedItemInventoryTypeMask; // 2 m_equippedItemInvTypes (mask)
int32 EquippedItemSubClassMask; // 3 m_equippedItemSubclass (mask)
};
// SpellFocusObject.dbc
struct SpellFocusObjectEntry
{
uint32 ID; // 0 m_ID
//char* Name; // 1 m_name_lang
};
// SpellInterrupts.dbc
struct SpellInterruptsEntry
{
//uint32 Id; // 0 m_ID
uint32 AuraInterruptFlags; // 33 m_auraInterruptFlags
//uint32 // 34 4.0.0
uint32 ChannelInterruptFlags; // 35 m_channelInterruptFlags
//uint32 // 36 4.0.0
uint32 InterruptFlags; // 32 m_interruptFlags
uint32 AuraInterruptFlags; // 1 m_auraInterruptFlags
//uint32 // 2 4.0.0
uint32 ChannelInterruptFlags; // 3 m_channelInterruptFlags
//uint32 // 4 4.0.0
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
struct SpellLevelsEntry
{
//uint32 Id; // 0 m_ID
uint32 baseLevel; // 41 m_baseLevel
uint32 maxLevel; // 40 m_maxLevel
uint32 spellLevel; // 42 m_spellLevel
uint32 baseLevel; // 1 m_baseLevel
uint32 maxLevel; // 2 m_maxLevel
uint32 spellLevel; // 3 m_spellLevel
};
// SpellPower.dbc
@ -1892,9 +1961,31 @@ struct SpellPowerEntry
uint32 manaCostPerlevel; // 2 - m_manaCostPerLevel
uint32 ManaCostPercentage; // 3 - m_manaCostPct
uint32 manaPerSecond; // 4 - m_manaPerSecond
//uint32 PowerDisplayId; // 5 - m_powerDisplayID - id from PowerDisplay.dbc, new in 3.1
//uint32 unk1; // 6 - 4.0.0
//unk // 7 - 4.3.0
uint32 manaPerSecondPerLevel; // 5 m_manaPerSecondPerLevel
//uint32 PowerDisplayId; // 6 - m_powerDisplayID - id from PowerDisplay.dbc, new in 3.1
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
@ -1905,19 +1996,30 @@ struct SpellReagentsEntry
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
struct SpellScalingEntry
{
//uint32 Id; // 0 m_ID
int32 castTimeMin; // 1
int32 castTimeMax; // 2
int32 castScalingMaxLevel; // 3
int32 playerClass; // 4 (index * 100) + charLevel => gtSpellScaling.dbc
uint32 castTimeMin; // 1
uint32 castTimeMax; // 2
uint32 castScalingMaxLevel; // 3
uint32 playerClass; // 4 (index * 100) + charLevel => gtSpellScaling.dbc
float coeff1[3]; // 5-7
float coeff2[3]; // 8-10
float coeff3[3]; // 11-13
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; };
};
@ -1926,11 +2028,30 @@ struct SpellScalingEntry
struct SpellShapeshiftEntry
{
//uint32 Id; // 0 m_ID
uint32 StancesNot; // 13 m_shapeshiftMask
// uint32 unk_320_2; // 14 3.2.0
uint32 Stances; // 15 m_shapeshiftExclude
// uint32 unk_320_3; // 16 3.2.0
// uint32 StanceBarOrder; // 155 m_stanceBarOrder not used
uint32 StancesNot; // 1 m_shapeshiftMask
// uint32 unk_320_2; // 2 3.2.0
uint32 Stances; // 3 m_shapeshiftExclude
// uint32 unk_320_3; // 4 3.2.0
// 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
@ -1948,8 +2069,8 @@ struct SpellTargetRestrictionsEntry
struct SpellTotemsEntry
{
//uint32 Id; // 0 m_ID
uint32 TotemCategory[MAX_SPELL_TOTEM_CATEGORIES]; // 162-163 m_requiredTotemCategoryID
uint32 Totem[MAX_SPELL_TOTEMS]; // 52-53 m_totem
uint32 TotemCategory[MAX_SPELL_TOTEM_CATEGORIES]; // 1 2 m_requiredTotemCategoryID
uint32 Totem[MAX_SPELL_TOTEMS]; // 3 4 m_totem
};
// 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_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
{
uint32 ID; // 0 m_ID
@ -2190,36 +2249,6 @@ struct SpellDurationEntry
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
{
uint32 Id; // 0 m_id

View file

@ -44,11 +44,12 @@ const char ChrClassesEntryfmt[]="nixsxxxixiiiii";
const char ChrRacesEntryfmt[]="nxixiixixxxxixsxxxxxixxx";
const char ChrClassesXPowerTypesfmt[]="nii";
const char CinematicSequencesEntryfmt[] = "nxxxxxxxxx";
const char CreatureDisplayInfofmt[]="nxxifxxxxxxxxxxxx";
const char CreatureDisplayInfofmt[]="nixifxxxxxxxxxxxx";
const char CreatureDisplayInfoExtrafmt[] = "nixxxxxxxxxxxxxxxxxxx";
const char CreatureFamilyfmt[]="nfifiiiiixsx";
const char CreatureModelDatafmt[] = "nxxxxxxxxxxxxxxffxxxxxxxxxxxxxx";
const char CreatureSpellDatafmt[] = "niiiixxxx";
const char DestructibleModelDataFmt[] = "nixxxixxxxixxxxixxxxxxxx";
const char DestructibleModelDataFmt[] = "nixxxixxxxixxxxixxxxixxx";
const char DungeonEncounterfmt[]="niiiisxx";
const char CreatureTypefmt[]="nxx";
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_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_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_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_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_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_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_WALK_MODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
//OPCODE(CMSG_GM_NUKE_ACCOUNT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@ -1319,9 +1319,9 @@ void InitializeOpcodes()
//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(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(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(MSG_MOVE_GRAVITY_CHNG, 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_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(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(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 );

View file

@ -840,8 +840,8 @@ enum Opcodes
SMSG_SPLINE_SET_SWIM_BACK_SPEED = 0x1303,
SMSG_SPLINE_SET_TURN_RATE = 0x1304,
SMSG_SPLINE_MOVE_UNROOT = 0x75B6, // 4.3.4 15595
SMSG_SPLINE_MOVE_FEATHER_FALL = 0x1306,
SMSG_SPLINE_MOVE_NORMAL_FALL = 0x1307,
SMSG_SPLINE_MOVE_FEATHER_FALL = 0x3DA5, // 4.3.4 15595
SMSG_SPLINE_MOVE_NORMAL_FALL = 0x38B2, // 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_WATER_WALK = 0x50A2, // 4.3.4 15595
@ -1238,7 +1238,7 @@ enum Opcodes
CMSG_REMOVE_GLYPH = 0x148B,
CMSG_DUMP_OBJECTS = 0x148C,
SMSG_DUMP_OBJECTS_DATA = 0x148D,
CMSG_DISMISS_CRITTER = 0x4227,
CMSG_DISMISS_CRITTER = 0x4227, // 4.3.4 15595
SMSG_NOTIFY_DEST_LOC_SPELL_CAST = 0x148F,
CMSG_AUCTION_LIST_PENDING_SALES = 0x2C17, // 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_QUERY_VEHICLE_STATUS = 0x14A6,
SMSG_BATTLEGROUND_INFO_THROTTLED = 0x14A7,
SMSG_SET_VEHICLE_REC_ID = 0x14A8,
CMSG_RIDE_VEHICLE_INTERACT = 0x14A9,
CMSG_CONTROLLER_EJECT_PASSENGER = 0x14AA,
SMSG_SET_VEHICLE_REC_ID = 0x4115, // 4.3.4 15595
CMSG_RIDE_VEHICLE_INTERACT = 0x2705, // 4.3.4 15595
CMSG_CONTROLLER_EJECT_PASSENGER = 0x6927, // 4.3.4 15595
SMSG_PET_GUIDS = 0x2D26, // 4.3.4 15595
SMSG_CLIENTCACHE_VERSION = 0x2734, // 4.3.4 15595
CMSG_CHANGE_GDF_ARENA_RATING = 0x14AD,
@ -1376,7 +1376,7 @@ enum Opcodes
SMSG_SEND_ALL_COMBAT_LOG = 0x1515,
SMSG_OPEN_LFG_DUNGEON_FINDER = 0x0412, // 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,
CMSG_CLEAR_RANDOM_BG_WIN_TIME = 0x151A,
CMSG_CLEAR_HOLIDAY_BG_WIN_TIME = 0x151B,

View file

@ -451,7 +451,7 @@ enum SpellAttributesEx4
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_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
@ -3792,4 +3792,14 @@ enum TeleportLocation
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

View file

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

View file

@ -232,6 +232,7 @@ bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
return false;
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());
if (result)

View file

@ -40,15 +40,22 @@ void WorldSession::HandleInspectArenaTeamsOpcode(WorldPacket& recv_data)
recv_data >> guid;
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)
{
if (uint32 a_id = plr->GetArenaTeamId(i))
if (uint32 a_id = player->GetArenaTeamId(i))
{
if (ArenaTeam* at = sObjectMgr.GetArenaTeamById(a_id))
at->InspectStats(this, plr->GetObjectGuid());
}
if (ArenaTeam* arenaTeam = sObjectMgr.GetArenaTeamById(a_id))
arenaTeam->InspectStats(this, player->GetObjectGuid());
}
}
}

View file

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

View file

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

View file

@ -173,7 +173,14 @@ void CreatureLinkingMgr::LoadFromDB()
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)
{
// 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
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 COUNT(guid) FROM creature WHERE id=%u AND map=%u", pTmp->masterId, pTmp->mapId);
if (result)
QueryResult* result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id=%u AND map=%u LIMIT 2", pTmp->masterId, pTmp->mapId);
if (!result)
{
sLog.outErrorDb("`creature_linking_template` has FLAG_FOLLOW, but no master, (entry: %u, map: %u, master: %u)", slaveEntry, pTmp->mapId, pTmp->masterId);
return false;
}
if (result->GetRowCount() > 1)
{
if ((*result)[0].GetUInt32() > 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
bool CreatureLinkingMgr::IsLinkedEventTrigger(Creature* pCreature)
bool CreatureLinkingMgr::IsLinkedEventTrigger(Creature* pCreature) const
{
// Entry case
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
// 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();
}
// 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);
}
// This gives the information of a linked NPC (describes action when its ActionTrigger triggers)
// 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
CreatureLinkingMapBounds bounds = m_creatureLinkingGuidMap.equal_range(pCreature->GetGUIDLow());
for (CreatureLinkingMap::const_iterator iter = bounds.first; iter != bounds.second; ++iter)
CreatureLinkingMapBounds bounds = m_creatureLinkingGuidMap.equal_range(lowGuid);
for (CreatureLinkingMap::const_iterator iter = bounds.first; iter != bounds.second;)
return &(iter->second);
// 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)
{
if (iter->second.mapId == pCreature->GetMapId())
if (iter->second.mapId == mapId)
return &(iter->second);
}
return NULL;
return nullptr;
}
// Function to add slave-NPCs to the holder
@ -384,7 +405,7 @@ void CreatureLinkingHolder::AddMasterToHolder(Creature* pCreature)
// Check, if already stored
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())
return; // Already added
@ -432,11 +453,11 @@ void CreatureLinkingHolder::DoCreatureLinkingEvent(CreatureLinkingEvent eventTyp
{
if (pInfo->linkingFlag & reverseEventFlagFilter)
{
Creature* pMaster = NULL;
Creature* pMaster = nullptr;
if (pInfo->mapId != INVALID_MAP_ID) // entry case
{
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);
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
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)
return true;
// Do some calculations
float sX, sY, sZ, mX, mY, mZ;
pSlave->GetRespawnCoord(sX, sY, sZ);
float mX, mY, mZ, dx, dy;
pBoss->GetRespawnCoord(mX, mY, mZ);
float dx, dy;
dx = sX - mX;
dy = sY - mY;
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
bool CreatureLinkingHolder::CanSpawn(Creature* pCreature)
bool CreatureLinkingHolder::CanSpawn(Creature* pCreature) const
{
CreatureLinkingInfo const* pInfo = sCreatureLinkingMgr.GetLinkedTriggerInformation(pCreature);
if (!pInfo)
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->masterDBGuid)
return false; // This should never happen
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)
return pCreature->GetMap()->GetPersistentState()->GetCreatureRespawnTime(pInfo->masterDBGuid) > 0;
return !IsRespawnReady(pInfo->masterDBGuid, _map);
else
return true;
}
// Search for nearby master
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);
if (pMaster && IsSlaveInRangeOfBoss(pCreature, pMaster, pInfo->searchRange))
Creature* pMaster = _map->GetCreature(itr->second);
if (pMaster && IsSlaveInRangeOfBoss(pMaster, sx, sy, pInfo->searchRange))
{
if (pInfo->linkingFlag & FLAG_CANT_SPAWN_IF_BOSS_DEAD)
return pMaster->IsAlive();
@ -652,11 +717,11 @@ bool CreatureLinkingHolder::TryFollowMaster(Creature* pCreature)
if (!pInfo || !(pInfo->linkingFlag & FLAG_FOLLOW))
return false;
Creature* pMaster = NULL;
Creature* pMaster = nullptr;
if (pInfo->mapId != INVALID_MAP_ID) // entry case
{
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);
if (pMaster && IsSlaveInRangeOfBoss(pCreature, pMaster, pInfo->searchRange))

View file

@ -48,6 +48,7 @@
class Unit;
class Creature;
class Map;
// enum on which Events an action for linked NPCs can trigger
enum CreatureLinkingEvent
@ -111,17 +112,19 @@ class CreatureLinkingMgr
public: // Accessors
// 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.
bool IsLinkedMaster(Creature* pCreature);
bool IsLinkedMaster(Creature* pCreature) const;
// 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)
// 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:
typedef std::multimap < uint32 /*slaveEntry*/, CreatureLinkingInfo > CreatureLinkingMap;
@ -162,7 +165,7 @@ class CreatureLinkingHolder
void DoCreatureLinkingEvent(CreatureLinkingEvent eventType, Creature* pSource, Unit* pEnemy = NULL);
// 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
bool TryFollowMaster(Creature* pCreature);
@ -185,7 +188,7 @@ class CreatureLinkingHolder
typedef std::multimap < uint32 /*masterEntryOrGuid*/, InfoAndGuids > HolderMap;
typedef std::pair<HolderMap::iterator, HolderMap::iterator> HolderMapBounds;
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
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
void SetFollowing(Creature* pWho, Creature* pWhom);
// 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
HolderMap m_holderMap;

View file

@ -174,7 +174,7 @@ namespace MaNGOS
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)
@ -184,12 +184,12 @@ namespace MaNGOS
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)
{
return IsValidMapCoord(x, y, z) && finite(o);
return IsValidMapCoord(x, y, z) && std::isfinite(o);
}
}
#endif

View file

@ -42,6 +42,9 @@ char const* MAP_AREA_MAGIC = "AREA";
char const* MAP_HEIGHT_MAGIC = "MHGT";
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()
{
m_flags = 0;
@ -1061,6 +1064,23 @@ bool TerrainInfo::IsInWater(float x, float y, float pZ, GridMapLiquidData* data)
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
{
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 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 IsSwimmable(float x, float y, float pZ, float radius = 1.5f, GridMapLiquidData* data = nullptr) const;
bool IsUnderWater(float x, float y, float z) 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,
MASTER_LOOT = 2,
GROUP_LOOT = 3,
NEED_BEFORE_GREED = 4
NEED_BEFORE_GREED = 4,
NOT_GROUP_TYPE_LOOT = 5 // internal use only
};
enum RollVote

View file

@ -71,7 +71,7 @@ bool WorldSession::CheckMailBox(ObjectGuid guid)
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
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;
}

View file

@ -298,13 +298,16 @@ bool Map::EnsureGridLoaded(const Cell& cell)
return false;
}
void Map::LoadGrid(const Cell& cell, bool no_unload)
void Map::ForceLoadGrid(float x, float y)
{
EnsureGridLoaded(cell);
if (no_unload)
if (!IsLoaded(x, y))
{
CellPair p = MaNGOS::ComputeCellPair(x, y);
Cell cell(p);
EnsureGridLoadedAtEnter(cell);
getNGrid(cell.GridX(), cell.GridY())->setUnloadExplicitLock(true);
}
}
bool Map::Add(Player* player)
{
@ -2116,6 +2119,61 @@ bool Map::GetHitPosition(float srcX, float srcY, float srcZ, float& destX, float
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 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(); }
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);
virtual void UnloadAll(bool pForce);
@ -194,7 +194,6 @@ class Map : public GridRefManager<NGridType>
MapDifficultyEntry const* GetMapDifficulty() const; // dependent from map difficulty
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 IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); }
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 IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); }
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
MapPersistentState* GetPersistentState() const { return m_persistentState; }

View file

@ -92,30 +92,30 @@ void MapManager::InitializeVisibilityDistanceInfo()
(*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)
{
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);
Map* m = NULL;
Map* m = nullptr;
const MapEntry* entry = sMapStore.LookupEntry(id);
if (!entry)
return NULL;
return nullptr;
if (entry->Instanceable())
{
MANGOS_ASSERT(obj->GetTypeId() == TYPEID_PLAYER);
MANGOS_ASSERT(obj && obj->GetTypeId() == TYPEID_PLAYER);
// create DungeonMap object
if (obj->GetTypeId() == TYPEID_PLAYER)
m = CreateInstance(id, (Player*)obj);
// Load active objects for this map
sObjectMgr.LoadActiveEntities(m);
}
else
{
// create regular non-instanceable map
m = FindMap(id);
if (m == NULL)
if (m == nullptr)
{
m = new WorldMap(id, i_gridCleanUpDelay);
// add map into container

View file

@ -94,7 +94,6 @@ class MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::ClassLevelLockab
i_timer.Reset();
}
// void LoadGrid(int mapid, int instId, float x, float y, const WorldObject* obj, bool no_unload = false);
void UnloadAll();
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...
if (GetPlayer()->IsInCombat() || //...is in combat
GetPlayer()->duel || //...is in Duel
//...is jumping ...is falling
GetPlayer()->m_movementInfo.HasMovementFlag(MovementFlags(MOVEFLAG_FALLING | MOVEFLAG_FALLINGFAR)))
{
@ -1082,12 +1081,16 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
recv_data >> guid;
DEBUG_LOG("Inspected guid is %s", guid.GetString().c_str());
_player->SetSelectionGuid(guid);
Player* plr = sObjectMgr.GetPlayer(guid);
if (!plr) // wrong player
return;
if (!_player->IsWithinDistInMap(plr, INSPECT_DISTANCE, false))
return;
if (_player->IsHostileTo(plr))
return;
WorldPacket data(SMSG_INSPECT_RESULTS, 50);
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);
Player* player = sObjectMgr.GetPlayer(guid);
if (!player)
{
sLog.outError("InspectHonorStats: WTF, player not found...");
return;
}
if (!_player->IsWithinDistInMap(player, INSPECT_DISTANCE, false))
return;
if (_player->IsHostileTo(player))
return;
WorldPacket data(SMSG_INSPECT_HONOR_STATS, 18);
data.WriteGuidMask<4, 3, 6, 2, 5, 0, 7, 1>(player->GetObjectGuid());
data << uint8(0); // rank
@ -1520,7 +1528,16 @@ void WorldSession::HandleQueryInspectAchievementsOpcode(WorldPacket& recv_data)
recv_data >> guid.ReadAsPacked();
if (Player* player = sObjectMgr.GetPlayer(guid))
Player* player = sObjectMgr.GetPlayer(guid);
if (!player)
return;
if (!_player->IsWithinDistInMap(player, INSPECT_DISTANCE, false))
return;
if (_player->IsHostileTo(player))
return;
player->GetAchievementMgr().SendRespondInspectAchievements(_player);
}

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)
{
ObjectGuid npcGuid;

View file

@ -43,6 +43,10 @@ void WorldSession::HandleLearnTalentOpcode(WorldPacket& recv_data)
_player->SendTalentsInfoData(false);
else
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)
@ -84,6 +88,10 @@ void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
}
_player->SendTalentsInfoData(false);
// if player has a pet, update owner talent auras
if (_player->GetPet())
_player->GetPet()->CastOwnerTalentAuras();
}
void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recv_data)
@ -99,9 +107,8 @@ void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recv_data)
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if (!unit->CanTrainAndResetTalentsOf(_player))
return;
if (!(_player->resetTalents()))
{
@ -114,6 +121,8 @@ void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recv_data)
_player->SendTalentsInfoData(false);
unit->CastSpell(_player, 14867, true); // spell: "Untalent Visual Effect"
if (_player->GetPet())
_player->GetPet()->CastOwnerTalentAuras();
}
void WorldSession::HandleUnlearnSkillOpcode(WorldPacket& recv_data)

View file

@ -520,8 +520,8 @@ void Spell::FillTargetMap()
// for TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT (A) all is checked in Spell::CheckCast and in Spell::CheckItem
// filled in Spell::CheckCast call
if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES ||
spellEffect->EffectImplicitTargetA == TARGET_SCRIPT ||
spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT ||
(spellEffect->EffectImplicitTargetA == TARGET_SCRIPT && spellEffect->EffectImplicitTargetB != TARGET_SELF) ||
(spellEffect->EffectImplicitTargetB == TARGET_SCRIPT && spellEffect->EffectImplicitTargetA != TARGET_SELF))
continue;
@ -571,8 +571,9 @@ void Spell::FillTargetMap()
case TARGET_SELF:
switch(spellEffect->EffectImplicitTargetB)
{
case TARGET_NONE:
case TARGET_NONE: // Fill Target based on A only
case TARGET_EFFECT_SELECT:
case TARGET_SCRIPT: // B-target only used with CheckCast here
SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]);
break;
case TARGET_AREAEFFECT_INSTANT: // use B case that not dependent from from A in fact
@ -716,6 +717,17 @@ void Spell::FillTargetMap()
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:
switch(spellEffect->EffectImplicitTargetB)
{
@ -3273,6 +3285,9 @@ void Spell::cast(bool skipCheck)
// Chaos Bane strength buff
else if (m_spellInfo->Id == 71904)
AddTriggeredSpell(73422);
// Weak Alcohol
else if (m_spellInfo->SpellIconID == 1306 && m_spellInfo->SpellVisual[0] == 11359)
AddTriggeredSpell(51655); // BOTM - Create Empty Brew Bottle
break;
}
case SPELLFAMILY_MAGE:
@ -3710,14 +3725,20 @@ void Spell::update(uint32 difftime)
SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(EFFECT_INDEX_0);
SpellInterruptsEntry const* spellInterrupts = m_spellInfo->GetSpellInterrupts();
// check if the player caster has moved before the spell finished
if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) &&
if (m_CastItemGuid && !m_CastItem)
{
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()) &&
((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))
{
// 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();
// don't cancel for melee, autorepeat, triggered and instant spells
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_caster->GetTypeId() == TYPEID_PLAYER)
if (m_caster->GetTypeId() == TYPEID_PLAYER || m_caster->GetTypeId() == TYPEID_UNIT)
{
// 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))
cancel();
// check for incapacitating player states
if (m_caster->hasUnitState(UNIT_STAT_CAN_NOT_REACT))
{
// 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
if( spellInterrupts && (spellInterrupts->ChannelInterruptFlags & CHANNEL_FLAG_TURNING) && m_castOrientation != m_caster->GetOrientation() )
@ -3790,7 +3815,7 @@ void Spell::update(uint32 difftime)
continue;
Unit* unit = m_caster->GetObjectGuid() == target.targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target.targetGUID);
if (unit == NULL)
if (unit == nullptr)
continue;
p->RewardPlayerAndGroupAtCast(unit, m_spellInfo->Id);
@ -4082,7 +4107,7 @@ void Spell::SendSpellStart()
data << uint8(m_runesState);
data << uint8(caster->GetRunesState());
for (uint8 i = 0; i < MAX_RUNES; ++i)
data << uint8(255 - ((caster->GetRuneCooldown(i) / REGEN_TIME_FULL) * 51));
data << uint8(caster->GetRuneCooldownFraction(i));
}
else
{
@ -4702,6 +4727,7 @@ void Spell::TakePower()
if (m_spellInfo->powerType == POWER_HEALTH)
{
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;
}
@ -4740,14 +4766,14 @@ void Spell::TakePower()
if (powerType == POWER_RUNE)
{
CheckOrTakeRunePower(hit);
TakeRunePower(hit);
return;
}
m_caster->ModifyPower(powerType, -(int32)m_powerCost);
}
SpellCastResult Spell::CheckOrTakeRunePower(bool take)
SpellCastResult Spell::CheckRunePower()
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_CAST_OK;
@ -4758,83 +4784,127 @@ SpellCastResult Spell::CheckOrTakeRunePower(bool take)
return SPELL_CAST_OK;
SpellRuneCostEntry const* src = sSpellRuneCostStore.LookupEntry(m_spellInfo->runeCostID);
if (!src || (src->NoRuneCost() && (!take || src->NoRunicPowerGain())))
if (!src)
return SPELL_CAST_OK;
m_runesState = plr->GetRunesState(); // store previous state
if (src->NoRuneCost())
return SPELL_CAST_OK;
// 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 (uint8 i = 0; i < RUNE_DEATH; ++i)
for (uint32 i = 0; i < RUNE_DEATH; ++i)
{
runeCost[i] = src->RuneCost[i];
if (Player* modOwner = plr->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i]);
}
runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
// scan non-death runes (death rune not used explicitly in rune costs)
for (uint8 i = 0; i < MAX_RUNES; ++i)
{
// already used
if (plr->GetRuneCooldown(i) != 0)
continue;
RuneType rune = plr->GetCurrentRune(i);
if (plr->GetRuneCooldown(i) == 0 && runeCost[rune] > 0)
for (uint32 i = 0; i < MAX_RUNES; ++i)
{
RuneType rune = plr->GetCurrentRune(i);
if (runeCost[rune] <= 0)
continue;
if (!plr->GetRuneCooldown(i) && runeCost[rune] > 0)
--runeCost[rune];
}
// already used
if (plr->GetRuneCooldown(i) != 0)
continue;
for (uint32 i = 0; i < RUNE_DEATH; ++i)
if (runeCost[i] > 0)
runeCost[RUNE_DEATH] += runeCost[i];
if (take)
plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec
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)
{
uint16 baseCd = hit ? uint16(RUNE_BASE_COOLDOWN) : uint16(RUNE_MISS_COOLDOWN);
plr->SetBaseRuneCooldown(i, baseCd);
plr->SetRuneCooldown(i, baseCd);
plr->SetLastUsedRune(rune);
--runeCost[rune];
}
}
// collect all not counted rune costs to death runes cost
for (uint8 i = 0; i < RUNE_DEATH; ++i)
if (runeCost[i] > 0)
runeCost[RUNE_DEATH] += runeCost[i];
runeCost[RUNE_DEATH] = runeCost[RUNE_BLOOD] + runeCost[RUNE_UNHOLY] + runeCost[RUNE_FROST];
// scan death runes
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);
if (!plr->GetRuneCooldown(i) && rune == RUNE_DEATH)
{
plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec
runeCost[rune]--;
uint16 baseCd = hit ? uint16(RUNE_BASE_COOLDOWN) : uint16(RUNE_MISS_COOLDOWN);
plr->SetBaseRuneCooldown(i, baseCd);
plr->SetRuneCooldown(i, baseCd);
plr->SetLastUsedRune(rune);
--runeCost[rune];
if (take)
plr->ConvertRune(i, plr->GetBaseRune(i));
// keep Death Rune type if missed
if (hit)
plr->RestoreBaseRune(i);
if (runeCost[RUNE_DEATH] == 0)
return SPELL_FAILED_NO_POWER;
break;
}
}
}
if (take)
if (hit)
{
// you can gain some runic power when use runes
float rp = float(src->runePowerGain);
rp *= sWorld.getConfig(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_INCOME);
int32 rp = int32(src->runePowerGain);
if (rp)
{
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, rp);
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);
}
return SPELL_CAST_OK;
}
}
void Spell::TakeReagents()
@ -5437,12 +5507,12 @@ SpellCastResult Spell::CheckCast(bool strict)
continue;
if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT ||
(spellEffect->EffectImplicitTargetB == TARGET_SCRIPT && spellEffect->EffectImplicitTargetA != TARGET_SELF) ||
spellEffect->EffectImplicitTargetB == TARGET_SCRIPT ||
spellEffect->EffectImplicitTargetA == 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);
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)
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);
}
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
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* creatureScriptTarget = NULL;
GameObject* goScriptTarget = NULL;
@ -5905,12 +5979,6 @@ SpellCastResult Spell::CheckCast(bool strict)
if (ReqValue > skillValue)
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;
}
case SPELL_EFFECT_OPEN_LOCK:
@ -5962,9 +6030,10 @@ SpellCastResult Spell::CheckCast(bool strict)
if (res != SPELL_CAST_OK)
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
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;
@ -5972,7 +6041,6 @@ SpellCastResult Spell::CheckCast(bool strict)
if ((canFailAtMax || skillValue < sWorld.GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue - 25, skillValue + 37))
return SPELL_FAILED_TRY_AGAIN;
}
break;
}
case SPELL_EFFECT_SUMMON_DEAD_PET:
{
@ -6823,7 +6891,7 @@ SpellCastResult Spell::CheckPower()
// check rune cost only if a spell has PowerType == POWER_RUNE
if (m_spellInfo->powerType == POWER_RUNE)
{
SpellCastResult failReason = CheckOrTakeRunePower(false);
SpellCastResult failReason = CheckRunePower();
if (failReason != SPELL_CAST_OK)
return failReason;
}

View file

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

View file

@ -363,7 +363,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS] =
&Aura::HandleNULL, //297 14 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::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::HandleUnused, //302 unused (3.2.2a-4.3.4)
&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,
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;
@ -751,18 +752,26 @@ void AreaAura::Update(uint32 diff)
// flag for selection is need apply aura to current iteration target
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
// 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)
{
if (i->second->IsDeleted())
{ continue; }
continue;
Aura* aur = i->second->GetAuraByEffectIndex(m_effIndex);
if (!aur)
{ continue; }
continue;
switch (m_areaAuraType)
{
@ -787,18 +796,16 @@ void AreaAura::Update(uint32 diff)
}
if (!apply)
{ continue; }
continue;
// 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)
{ continue; }
if (actualSpellInfo->HasAttribute(SPELL_ATTR_EX3_TARGET_ONLY_PLAYER) && (*tIter)->GetTypeId() != TYPEID_PLAYER)
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); }
actualBasePoints = actualSpellInfo->CalculateSimpleValue(m_effIndex);
SpellAuraHolder* holder = (*tIter)->GetSpellAuraHolder(actualSpellInfo->Id, GetCasterGuid());
@ -811,7 +818,7 @@ void AreaAura::Update(uint32 diff)
holder->SetAuraDuration(GetAuraDuration());
AreaAura* aur = new AreaAura(actualSpellInfo, m_effIndex, &actualBasePoints, holder, (*tIter), caster, NULL);
AreaAura* aur = new AreaAura(actualSpellInfo, m_effIndex, &actualBasePoints, holder, (*tIter), caster, nullptr, GetSpellProto()->Id);
holder->AddAura(aur, m_effIndex);
if (addedToExisting)
@ -823,7 +830,7 @@ void AreaAura::Update(uint32 diff)
}
else
(*tIter)->AddSpellAuraHolder(holder);
}
}
}
Aura::Update(diff);
@ -832,6 +839,7 @@ void AreaAura::Update(uint32 diff)
{
Unit* caster = GetCaster();
Unit* target = GetTarget();
uint32 originalRankSpellId = m_originalRankSpellId ? m_originalRankSpellId : GetId(); // caster may have different spell id if target has lower level
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 (no longer) friendly
bool needFriendly = (m_areaAuraType == AREA_AURA_ENEMY ? false : true);
if (!caster || caster->hasUnitState(UNIT_STAT_ISOLATED) ||
if (!caster ||
caster->hasUnitState(UNIT_STAT_ISOLATED) ||
!caster->HasAura(originalRankSpellId, GetEffIndex()) ||
!caster->IsWithinDistInMap(target, m_radius) ||
!caster->HasAura(GetId(), GetEffIndex()) ||
caster->IsFriendlyTo(target) != needFriendly
)
{
@ -854,29 +863,29 @@ void AreaAura::Update(uint32 diff)
{
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
Group* pGroup = check ? check->GetGroup() : NULL;
Group* pGroup = check ? check->GetGroup() : nullptr;
if (pGroup)
{
Player* checkTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!checkTarget || !pGroup->SameSubGroup(check, checkTarget))
{ target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid()); }
target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
}
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
if (caster->GetCharmerOrOwnerGuid() != target->GetObjectGuid() && caster->GetObjectGuid() != target->GetCharmerOrOwnerGuid())
{
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
Group* pGroup = check ? check->GetGroup() : NULL;
Group* pGroup = check ? check->GetGroup() : nullptr;
if (pGroup)
{
Player* checkTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!checkTarget)
if (!checkTarget || !checkTarget->GetGroup() || checkTarget->GetGroup()->GetId() != pGroup->GetId())
target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
}
else
@ -886,7 +895,7 @@ void AreaAura::Update(uint32 diff)
else if (m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER)
{
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 };
triggerTarget->CastCustomSpell(triggerTarget, 19698, &damageForTick[GetAuraTicks() - 1], nullptr, nullptr, true, nullptr);
return;
return;;
}
// // Frostwolf Muzzle DND
@ -3526,62 +3535,18 @@ void Aura::HandleAuraFeatherFall(bool apply, bool Real)
{
// only at real add/remove aura
if (!Real)
{ return; }
Unit* target = GetTarget();
WorldPacket data;
target->BuildMoveFeatherFallPacket(&data, apply, 0);
target->SendMessageToSet(&data, true);
return;
// start fall from current height
if (!apply && target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->SetFallInformation(0, target->GetPositionZ());
GetTarget()->SetFeatherFall(apply);
}
void Aura::HandleAuraHover(bool apply, bool Real)
{
// only at real add/remove aura
if (!Real)
{ return; }
return;
WorldPacket data;
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);
GetTarget()->SetHover(apply);
}
void Aura::HandleWaterBreathing(bool /*apply*/, bool /*Real*/)
@ -4069,8 +4034,7 @@ void Aura::HandleAuraTransform(bool apply, bool Real)
if (Unit* caster = GetCaster())
if (caster->HasAura(52648)) // Glyph of the Penguin
model_id = 26452;
else
if (caster->HasAura(57927)) // Glyph of the Monkey
else if (caster->HasAura(57927)) // Glyph of the Monkey
model_id = 21362;
target->SetDisplayId(model_id);
@ -5209,9 +5173,7 @@ void Aura::HandleAuraModIncreaseFlightSpeed(bool apply, bool Real)
// Enable Fly mode for flying mounts
if (m_modifier.m_auraname == SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED)
{
WorldPacket data;
target->BuildMoveSetCanFlyPacket(&data, apply, 0);
target->SendMessageToSet(&data, true);
target->SetCanFly(apply);
// Players on flying mounts must be immune to polymorph
if (target->GetTypeId() == TYPEID_PLAYER)
@ -7109,10 +7071,7 @@ void Aura::HandleAuraAllowFlight(bool apply, bool Real)
if (!Real)
return;
// allow fly
WorldPacket data;
GetTarget()->BuildMoveSetCanFlyPacket(&data, apply, 0);
GetTarget()->SendMessageToSet(&data, true);
GetTarget()->SetCanFly(apply);
}
void Aura::HandleModRating(bool apply, bool Real)

View file

@ -545,13 +545,14 @@ class Aura
class AreaAura : public Aura
{
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();
protected:
void Update(uint32 diff) override;
private:
float m_radius;
AreaAuraType m_areaAuraType;
uint32 m_originalRankSpellId;
};
class PersistentAreaAura : public Aura

View file

@ -222,7 +222,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS] =
&Spell::EffectQuestOffer, //150 SPELL_EFFECT_QUEST_OFFER
&Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
&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::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
@ -4191,17 +4191,12 @@ void Spell::EffectTriggerSpell(SpellEffectEntry const* effect)
pet->CastSpell(pet, 28305, true);
return;
}
case 53258: // Empower Rune Weapon
case 58832: // Mirror Image
{
// remove cooldown of frost/death, undead/blood activated in main spell
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
{
bool res1 = ((Player*)unitTarget)->ActivateRunes(RUNE_FROST, 2);
bool res2 = ((Player*)unitTarget)->ActivateRunes(RUNE_DEATH, 2);
if (res1 || res2)
((Player*)unitTarget)->ResyncRunes();
}
return;
// Glyph of Mirror Image
if (m_caster->HasAura(63093))
m_caster->CastSpell(m_caster, 65047, true, m_CastItem, nullptr, m_originalCasterGUID);
break;
}
}
@ -4339,7 +4334,11 @@ void Spell::EffectJump(SpellEffectEntry const* effect)
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!
@ -6629,56 +6628,45 @@ void Spell::EffectSummonPet(SpellEffectEntry const* effect)
{
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;
// petentry==0 for hunter "call pet" (current pet summoned if any)
if (m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster, petentry))
return;
// not error in case fail hunter call pet
if (!petentry)
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
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;
return;
}
@ -6695,29 +6683,38 @@ void Spell::EffectSummonPet(SpellEffectEntry const* effect)
NewSummon->SetRespawnCoord(pos);
uint32 petlevel = m_caster->getLevel();
NewSummon->setPetType(SUMMON_PET);
// Level of pet summoned
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->SetOwnerGuid(m_caster->GetObjectGuid());
NewSummon->SetCreatorGuid(m_caster->GetObjectGuid());
NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
NewSummon->setFaction(faction);
NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL)));
NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
NewSummon->setFaction(m_caster->getFaction());
NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(nullptr)));
NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
NewSummon->InitStatsForLevel(level);
NewSummon->InitPetCreateSpells();
NewSummon->InitLevelupSpellsForLevel();
NewSummon->InitTalentForLevel();
map->Add((Creature*)NewSummon);
NewSummon->AIM_Initialize();
m_caster->SetPet(NewSummon);
DEBUG_LOG("New Pet has guid %u", NewSummon->GetGUIDLow());
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);
// this enables pet details window (Shift+P)
// generate new name for summon pet
NewSummon->SetName(sObjectMgr.GeneratePetName(petentry));
if (m_caster->IsPvP())
NewSummon->SetPvP(true);
@ -6725,39 +6722,26 @@ void Spell::EffectSummonPet(SpellEffectEntry const* effect)
if (m_caster->IsFFAPvP())
NewSummon->SetFFAPvP(true);
NewSummon->InitStatsForLevel(petlevel, m_caster);
NewSummon->InitPetCreateSpells();
NewSummon->InitLevelupSpellsForLevel();
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);
m_caster->SetPet(NewSummon);
DEBUG_LOG("New Pet has guid %u", NewSummon->GetGUIDLow());
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
((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)
@ -11490,7 +11474,7 @@ void Spell::EffectActivateRune(SpellEffectEntry const* effect)
return;
int32 count = damage; // max amount of reset runes
if (plr->ActivateRunes(RuneType(effect->EffectMiscValue), count))
plr->ResyncRunes();
}

View file

@ -186,6 +186,14 @@ void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recv_data)
{
uint32 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);
}
@ -282,5 +290,14 @@ void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recv_data)
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);
}

View file

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

View file

@ -34,6 +34,7 @@
#include "Log.h"
// #include "ObjectMgr.h" // chucky delete ?
#include "Util.h"
#include "ProgressBar.h"
#ifdef ENABLE_ELUNA
#include "LuaEngine.h"
#endif /* ENABLE_ELUNA */
@ -155,7 +156,7 @@ bool Weather::ReGenerate()
uint32 chance2 = chance1 + m_weatherChances->data[season].snowChance;
uint32 chance3 = chance2 + m_weatherChances->data[season].stormChance;
uint32 rnd = urand(0, 99);
uint32 rnd = urand(1, 100);
if (rnd <= chance1)
{
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
///- Empty the kicked session set
std::for_each(m_sessions.begin(), m_sessions.end(), [](const SessionMap::value_type &p) { delete p.second; });
m_sessions.clear();
for (auto const session : m_sessions)
delete session.second;
std::for_each(m_cliCommandQueue.begin(), m_cliCommandQueue.end(), [](const CliCommandHolder *p) { delete p; });
m_cliCommandQueue.clear();
for (auto const cliCommand : m_cliCommandQueue)
delete cliCommand;
std::for_each(m_sessionAddQueue.begin(), m_sessionAddQueue.end(), [](const WorldSession *s) { delete s; });
m_sessionAddQueue.clear();
for (auto const session : m_sessionAddQueue)
delete session;
VMAP::VMapFactory::clear();
MMAP::MMapFactory::clear();
delete m_configForceLoadMapIds;
}
/// Cleanups before world stop
@ -577,6 +575,17 @@ void World::LoadConfigSettings(bool reload)
setConfig(CONFIG_BOOL_ADDON_CHANNEL, "AddonChannel", true);
setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB, "CleanCharacterDB", 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);
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);
@ -635,7 +644,7 @@ void World::LoadConfigSettings(bool reload)
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_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_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);
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_SCORE_STATISTICS, "Battleground.ScoreStatistics", false);
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_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)
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?
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; }
@ -766,9 +769,10 @@ class World
// used versions
std::string m_DBVersion;
std::string m_CreatureEventAIVersion;
// List of Maps that should be force-loaded on startup
std::set<uint32>* m_configForceLoadMapIds;
std::set<uint32> m_configForceLoadMapIds;
};
extern uint32 realmID;

View file

@ -171,7 +171,7 @@ namespace Movement
{
// mix existing state into new
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)

View file

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

View file

@ -30,7 +30,7 @@ using namespace G3D;
namespace VMAP
{
void chompAndTrim(std::string& str)
void VMapFactory::chompAndTrim(std::string& str)
{
while (str.length() > 0)
{
@ -64,7 +64,7 @@ namespace VMAP
//===============================================
// 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;
unsigned int i;

View file

@ -43,6 +43,9 @@ namespace VMAP
static void preventSpellsFromBeingTestedForLoS(const char* pSpellIdString);
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

View file

@ -113,6 +113,12 @@ BindIP = "0.0.0.0"
# Default: 1 (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
# Grid clean up delay (in milliseconds)
# Default: 300000 (5 min)
@ -207,6 +213,7 @@ PlayerLimit = 100
SaveRespawnTimeImmediately = 1
MaxOverspeedPings = 2
GridUnload = 1
LoadAllGridsOnMaps = ""
GridCleanUpDelay = 300000
MapUpdateInterval = 100
ChangeWeatherInterval = 600000
@ -1487,6 +1494,11 @@ Death.Ghost.RunSpeed.Battleground = 1.0
# 1 (send to joined player only)
# 2 (send to all players)
#
# Battleground.ScoreStatistics
# Enable Battleground scores storage in database
# Default: 0 (disable)
# 1 (enable)
#
# Battleground.QueueAnnouncer.Start
# Enable queue announcer posting to chat at BG start
# Default: 0 (disable)
@ -1512,6 +1524,7 @@ Death.Ghost.RunSpeed.Battleground = 1.0
Battleground.CastDeserter = 1
Battleground.QueueAnnouncer.Join = 0
Battleground.QueueAnnouncer.Start = 0
Battleground.ScoreStatistics = 0
Battleground.InvitationType = 0
BattleGround.PrematureFinishTimer = 300000
BattleGround.PremadeGroupWaitForMatch = 1800000

View file

@ -105,7 +105,7 @@ namespace LuaUnit
Creature* creature = Eluna::CHECKOBJ<Creature>(L, 2);
#ifndef TRINITY
Eluna::Push(L, unit->isInAccessablePlaceFor(creature));
Eluna::Push(L, unit->IsInAccessablePlaceFor(creature));
#else
Eluna::Push(L, unit->isInAccessiblePlaceFor(creature));
#endif
@ -1707,12 +1707,12 @@ namespace LuaUnit
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->CombatStopWithPets();
}
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;
}

View file

@ -184,7 +184,7 @@ bool npc_escortAI::AssistPlayerInCombat(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
if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombat(pWho))

View file

@ -122,7 +122,7 @@ bool FollowerAI::AssistPlayerInCombat(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
if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombat(pWho))

View file

@ -56,7 +56,7 @@ void ScriptedPetAI::MoveInLineOfSight(Unit* pWho)
}
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)
{

View file

@ -74,7 +74,7 @@ bool ScriptedAI::IsVisible(Unit* pWho) const
void ScriptedAI::MoveInLineOfSight(Unit* pWho)
{
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)
{

View file

@ -59,14 +59,14 @@ struct npc_ragged_john : public CreatureScript
{
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);
((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)
{

View file

@ -1247,7 +1247,7 @@ struct horde_defender : public CreatureScript
void MoveInLineOfSight(Unit* u) override
{
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;
if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->IsWithinLOSInMap(u))
@ -1330,7 +1330,7 @@ struct kolkar_invader : public CreatureScript
void MoveInLineOfSight(Unit* u) override
{
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;
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
{
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))
{

View file

@ -179,9 +179,12 @@ struct npc_ancestral_wolf : public CreatureScript
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
{
switch (uiPointId)

View file

@ -72,7 +72,7 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <cmath>
#include <errno.h>
#include <signal.h>
#include <assert.h>
@ -172,7 +172,7 @@ typedef off_t ACE_OFF_T;
* @param f
* @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)

View file

@ -65,7 +65,7 @@ uint32 WorldTimer::getMSTime_internal(bool savetime /*= false*/)
// calculate time diff between two world ticks
// 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!!!
uint64 diff = 0;
ACE_UINT64 diff = 0;
(currTime - g_SystemTickTime).msec(diff);
// lets calculate current world time

View file

@ -33,11 +33,11 @@
#define CHAR_DB_VERSION_NR 21
#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 WORLD_DB_VERSION_NR 21
#define WORLD_DB_STRUCTURE_NR 1
#define WORLD_DB_CONTENT_NR 0
#define WORLD_DB_STRUCTURE_NR 2
#define WORLD_DB_CONTENT_NR 3
#define WORLD_DB_UPDATE_DESCRIPTION "script_binding populated"
#endif // __REVISION_H__

View file

@ -67,19 +67,11 @@ else()
target_link_libraries(${EXECUTABLE_NAME} ACE)
endif()
target_link_libraries(${EXECUTABLE_NAME} g3dlite vmap detour recast zlib shared)
if(UNIX)
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
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()
target_link_libraries(${EXECUTABLE_NAME} rt)
endif()
if(APPLE)
set(EXECUTABLE_LINK_FLAGS "-framework CoreServices ${EXECUTABLE_LINK_FLAGS}")
endif()
target_link_libraries(${EXECUTABLE_NAME} g3dlite vmap detour recast zlib shared)
#Output the compiled exes to build/bin/$(Configuration)/tools directory on windows by default
if(WIN32)

View file

@ -47,22 +47,20 @@ else()
target_link_libraries(${EXECUTABLE_NAME} ACE)
endif()
if(UNIX)
target_link_libraries(${EXECUTABLE_NAME} rt dl)
endif()
target_link_libraries(${EXECUTABLE_NAME} vmap g3dlite zlib)
set(EXECUTABLE_LINK_FLAGS "")
if(UNIX)
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
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}")
if(CMAKE_C_COMPILER MATCHES "clang" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(EXECUTABLE_LINK_FLAGS "-pthread${EXECUTABLE_LINK_FLAGS}")
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}")
#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
)
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
if(WIN32)