Merge branch 'master' into 310

Conflicts:
	src/game/GameObject.cpp
This commit is contained in:
tomrus88 2009-03-18 07:45:29 +03:00
commit 9d2acc22b4
47 changed files with 1772 additions and 1246 deletions

View file

@ -689,12 +689,15 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
if(GetPlayer()->HasSpell(achievementCriteria->learn_spell.spellID))
// spell always provide and at login spell learning.
if(miscvalue1 && miscvalue1!=achievementCriteria->learn_spell.spellID)
continue;
if(GetPlayer()->HasSpell(miscvalue1))
SetCriteriaProgress(achievementCriteria, 1);
break;
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
// speedup for non-login case
if(miscvalue1 && achievementCriteria->own_item.itemID!=miscvalue1)
if(miscvalue1 && achievementCriteria->own_item.itemID != miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetItemCount(achievementCriteria->own_item.itemID, true));
break;
@ -736,6 +739,10 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
break;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
{
// skip faction check only at loading
if (miscvalue1 && miscvalue1 != achievementCriteria->gain_reputation.factionID)
continue;
int32 reputation = GetPlayer()->GetReputation(achievementCriteria->gain_reputation.factionID);
if (reputation > 0)
SetCriteriaProgress(achievementCriteria, reputation);
@ -743,6 +750,10 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
}
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
{
// skip faction check only at loading
if (miscvalue1 && GetPlayer()->GetReputationRank(miscvalue1) < REP_EXALTED)
continue;
uint32 counter = 0;
const FactionStateList factionStateList = GetPlayer()->GetFactionStateList();
for (FactionStateList::const_iterator iter = factionStateList.begin(); iter!= factionStateList.end(); ++iter)
@ -806,24 +817,43 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
// miscvalue1 = item_id
if(!miscvalue1)
continue;
if(miscvalue1 != achievementCriteria->equip_item.itemID)
continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
{
// spell always provide and at login spell learning.
if(!miscvalue1)
continue;
// rescan only when change possible
SkillLineAbilityMap::const_iterator skillIter0 = spellmgr.GetBeginSkillLineAbilityMap(miscvalue1);
if(skillIter0 == spellmgr.GetEndSkillLineAbilityMap(miscvalue1))
continue;
if(skillIter0->second->skillId != achievementCriteria->learn_skilline_spell.skillLine)
continue;
uint32 spellCount = 0;
for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin();
spellIter != GetPlayer()->GetSpellMap().end();
++spellIter)
{
uint32 spellCount = 0;
for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin();
spellIter != GetPlayer()->GetSpellMap().end();
++spellIter)
for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first);
skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first);
++skillIter)
{
for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first);
skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first);
++skillIter)
{
if(skillIter->second->skillId == achievementCriteria->learn_skilline_spell.skillLine)
spellCount++;
}
if(skillIter->second->skillId == achievementCriteria->learn_skilline_spell.skillLine)
spellCount++;
}
SetCriteriaProgress(achievementCriteria, spellCount);
break;
}
SetCriteriaProgress(achievementCriteria, spellCount);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
{
if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID)
@ -876,7 +906,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS:
case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
@ -1004,6 +1033,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
return progress->counter >= achievementCriteria->roll_greed_on_loot.count;
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
return progress->counter >= achievementCriteria->do_emote.count;
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
return progress->counter >= achievementCriteria->equip_item.count;
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
return progress->counter >= achievementCriteria->quest_reward_money.goldInCopper;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:

View file

@ -428,9 +428,10 @@ void BattleGround::Update(uint32 diff)
if(GetStatus() == STATUS_WAIT_LEAVE)
{
// remove all players from battleground after 2 minutes
m_EndTime += diff;
if(m_EndTime >= TIME_TO_AUTOREMOVE) // 2 minutes
m_EndTime -= diff;
if( m_EndTime <= 0)
{
m_EndTime = 0;
BattleGroundPlayerMap::iterator itr, next;
for(itr = m_Players.begin(); itr != m_Players.end(); itr = next)
{
@ -443,6 +444,8 @@ void BattleGround::Update(uint32 diff)
}
}
//update start time
m_StartTime += diff;
}
void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
@ -633,7 +636,8 @@ void BattleGround::EndBattleGround(uint32 winner)
}
SetStatus(STATUS_WAIT_LEAVE);
m_EndTime = 0;
//we must set it this way, because end time is sent in packet!
m_EndTime = TIME_TO_AUTOREMOVE;
// arena rating calculation
if(isArena() && isRated())
@ -716,7 +720,7 @@ void BattleGround::EndBattleGround(uint32 winner)
plr->GetSession()->SendPacket(&data);
BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType());
plr->GetSession()->SendPacket(&data);
plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1);
}
@ -964,7 +968,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
if(SendPacket)
{
WorldPacket data;
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0);
plr->GetSession()->SendPacket(&data);
}
@ -1155,10 +1159,15 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid,
if(group->IsMember(plr_guid))
{
uint8 subgroup = group->GetMemberGroup(plr_guid);
plr->SetGroup(group, subgroup);
plr->SetBattleGroundRaid(group, subgroup);
}
else
GetBgRaid(team)->AddMember(plr_guid, plr->GetName());
{
group->AddMember(plr_guid, plr->GetName());
if( Group* originalGroup = plr->GetOriginalGroup() )
if( originalGroup->IsLeader(plr_guid) )
group->ChangeLeader(plr_guid);
}
}
}
@ -1191,7 +1200,11 @@ void BattleGround::EventPlayerLoggedOut(Player* player)
if( isBattleGround() )
EventPlayerDroppedFlag(player);
else
CheckArenaWinConditions();
{
//1 player is logging out, if it is the last, then end arena!
if( GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam())) )
EndBattleGround(GetOtherTeam(player->GetTeam()));
}
}
}
@ -1589,7 +1602,7 @@ void BattleGround::EndNow()
{
RemoveFromBGFreeSlotQueue();
SetStatus(STATUS_WAIT_LEAVE);
SetEndTime(TIME_TO_AUTOREMOVE);
SetEndTime(0);
// inform invited players about the removal
sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
}
@ -1659,8 +1672,9 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer )
}
}
// to be able to remove insignia
player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
// to be able to remove insignia -- ONLY IN BattleGrounds
if( !isArena() )
player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
}
// return the player's team based on battlegroundplayer info
@ -1699,7 +1713,7 @@ void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player* plr)
sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
plr->GetSession()->SendPacket(&data);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType());
plr->GetSession()->SendPacket(&data);
}

View file

@ -530,7 +530,7 @@ class BattleGround
BattleGroundStatus m_Status;
uint32 m_ClientInstanceID; //the instance-id which is sent to the client and without any other internal use
uint32 m_StartTime;
uint32 m_EndTime;
int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself
uint32 m_LastResurrectTime;
BGQueueIdBasedOnLevel m_QueueId;
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5

View file

@ -48,7 +48,7 @@ void BattleGroundAB::Update(uint32 diff)
if( GetStatus() == STATUS_IN_PROGRESS )
{
int team_points[2] = { 0, 0 };
int team_points[BG_TEAMS_COUNT] = { 0, 0 };
for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
{
@ -88,24 +88,24 @@ void BattleGroundAB::Update(uint32 diff)
{
// FIXME: team and node names not localized
SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node));
PlaySoundToAll(SOUND_NODE_CAPTURED_ALLIANCE);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
}
else
{
// FIXME: team and node names not localized
SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE,NULL,LANG_BG_AB_HORDE,_GetNodeNameId(node));
PlaySoundToAll(SOUND_NODE_CAPTURED_HORDE);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
}
}
}
for (int team = 0; team < 2; ++team)
for (int team = 0; team < BG_TEAMS_COUNT; ++team)
if( m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED )
++team_points[team];
}
// Accumulate points
for (int team = 0; team < 2; ++team)
for (int team = 0; team < BG_TEAMS_COUNT; ++team)
{
int points = team_points[team];
if( !points )
@ -127,18 +127,18 @@ void BattleGroundAB::Update(uint32 diff)
RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE);
m_HonorScoreTics[team] -= m_HonorTics;
}
if( !m_IsInformedNearVictory && m_TeamScores[team] > 1800 )
if( !m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE )
{
if( team == BG_TEAM_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);
PlaySoundToAll(SOUND_NEAR_VICTORY);
PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY);
m_IsInformedNearVictory = true;
}
if( m_TeamScores[team] > 2000 )
m_TeamScores[team] = 2000;
if( m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE )
m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE;
if( team == BG_TEAM_ALLIANCE )
UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]);
if( team == BG_TEAM_HORDE )
@ -147,9 +147,9 @@ void BattleGroundAB::Update(uint32 diff)
}
// Test win condition
if( m_TeamScores[BG_TEAM_ALLIANCE] >= 2000 )
if( m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE )
EndBattleGround(ALLIANCE);
if( m_TeamScores[BG_TEAM_HORDE] >= 2000 )
if( m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE )
EndBattleGround(HORDE);
}
}
@ -313,7 +313,7 @@ void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
// Team scores
data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE);
data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_SCORE);
data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE);
data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]);
@ -440,7 +440,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
else
SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE);
sound = SOUND_NODE_CLAIMED;
sound = BG_AB_SOUND_NODE_CLAIMED;
}
// If node is contested
else if( (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED) )
@ -484,7 +484,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
else
SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
}
sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
}
// If node is occupied, change to enemy-contested
else
@ -506,7 +506,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
else
SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
}
// If node is occupied again, send "X has taken the Y" msg.

View file

@ -75,17 +75,17 @@ enum BG_AB_NodeObjectId
enum BG_AB_ObjectType
{
// for all 5 node points 8*5=40 objects
BG_AB_OBJECT_BANNER_NEUTRAL = 0,
BG_AB_OBJECT_BANNER_CONT_A = 1,
BG_AB_OBJECT_BANNER_CONT_H = 2,
BG_AB_OBJECT_BANNER_ALLY = 3,
BG_AB_OBJECT_BANNER_HORDE = 4,
BG_AB_OBJECT_AURA_ALLY = 5,
BG_AB_OBJECT_AURA_HORDE = 6,
BG_AB_OBJECT_AURA_CONTESTED = 7,
BG_AB_OBJECT_BANNER_NEUTRAL = 0,
BG_AB_OBJECT_BANNER_CONT_A = 1,
BG_AB_OBJECT_BANNER_CONT_H = 2,
BG_AB_OBJECT_BANNER_ALLY = 3,
BG_AB_OBJECT_BANNER_HORDE = 4,
BG_AB_OBJECT_AURA_ALLY = 5,
BG_AB_OBJECT_AURA_HORDE = 6,
BG_AB_OBJECT_AURA_CONTESTED = 7,
//gates
BG_AB_OBJECT_GATE_A = 40,
BG_AB_OBJECT_GATE_H = 41,
BG_AB_OBJECT_GATE_A = 40,
BG_AB_OBJECT_GATE_H = 41,
//buffs
BG_AB_OBJECT_SPEEDBUFF_STABLES = 42,
BG_AB_OBJECT_REGENBUFF_STABLES = 43,
@ -128,8 +128,8 @@ enum BG_AB_Timers
enum BG_AB_Score
{
BG_AB_MAX_TEAM_SCORE = 2000,
BG_AB_WARNING_SCORE = 1800
BG_AB_WARNING_NEAR_VICTORY_SCORE = 1800,
BG_AB_MAX_TEAM_SCORE = 2000
};
/* do NOT change the order, else wrong behaviour */
@ -162,18 +162,18 @@ enum BG_AB_NodeStatus
enum BG_AB_Sounds
{
SOUND_NODE_CLAIMED = 8192,
SOUND_NODE_CAPTURED_ALLIANCE = 8173,
SOUND_NODE_CAPTURED_HORDE = 8213,
SOUND_NODE_ASSAULTED_ALLIANCE = 8174,
SOUND_NODE_ASSAULTED_HORDE = 8212,
SOUND_NEAR_VICTORY = 8456
BG_AB_SOUND_NODE_CLAIMED = 8192,
BG_AB_SOUND_NODE_CAPTURED_ALLIANCE = 8173,
BG_AB_SOUND_NODE_CAPTURED_HORDE = 8213,
BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE = 8174,
BG_AB_SOUND_NODE_ASSAULTED_HORDE = 8212,
BG_AB_SOUND_NEAR_VICTORY = 8456
};
#define BG_AB_NotABBGWeekendHonorTicks 330
#define BG_AB_ABBGWeekendHonorTicks 200
#define BG_AB_NotABBGWeekendHonorTicks 330
#define BG_AB_ABBGWeekendHonorTicks 200
#define BG_AB_NotABBGWeekendReputationTicks 200
#define BG_AB_ABBGWeekendReputationTicks 150
#define BG_AB_ABBGWeekendReputationTicks 150
// x, y, z, o
const float BG_AB_NodePositions[BG_AB_DYNAMIC_NODES_COUNT][4] = {
@ -283,10 +283,10 @@ class BattleGroundAB : public BattleGround
uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT];
BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT];
int32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT];
uint32 m_TeamScores[2];
uint32 m_lastTick[2];
uint32 m_HonorScoreTics[2];
uint32 m_ReputationScoreTics[2];
uint32 m_TeamScores[BG_TEAMS_COUNT];
uint32 m_lastTick[BG_TEAMS_COUNT];
uint32 m_HonorScoreTics[BG_TEAMS_COUNT];
uint32 m_ReputationScoreTics[BG_TEAMS_COUNT];
bool m_IsInformedNearVictory;
uint32 m_HonorTics;
uint32 m_ReputationTics;

View file

@ -258,9 +258,20 @@ void BattleGroundEY::UpdatePointStatuses()
void BattleGroundEY::UpdateTeamScore(uint32 Team)
{
uint32 score = GetTeamScore(Team);
if(score >= EY_MAX_TEAM_SCORE)
//TODO there should be some sound played when one team is near victory!! - and define variables
/*if( !m_IsInformedNearVictory && score >= BG_EY_WARNING_NEAR_VICTORY_SCORE )
{
score = EY_MAX_TEAM_SCORE;
if( Team == ALLIANCE )
SendMessageToAll(LANG_BG_EY_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
else
SendMessageToAll(LANG_BG_EY_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_EY_SOUND_NEAR_VICTORY);
m_IsInformedNearVictory = true;
}*/
if( score >= BG_EY_MAX_TEAM_SCORE )
{
score = BG_EY_MAX_TEAM_SCORE;
EndBattleGround(Team);
}
@ -509,7 +520,7 @@ void BattleGroundEY::Reset()
m_PointAddingTimer = 0;
m_TowerCapCheckTimer = 0;
bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call!
uint32 m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks;
m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks;
for(uint8 i = 0; i < EY_POINTS_MAX; ++i)
{
@ -594,9 +605,9 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player *Source)
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN);
if(Source->GetTeam() == ALLIANCE)
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source);
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL);
else
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG,CHAT_MSG_BG_SYSTEM_HORDE, Source);
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL);
}
void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj)
@ -626,9 +637,9 @@ void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target
Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
if(Source->GetTeam() == ALLIANCE)
SendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source);
PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, Source->GetName());
else
SendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG,CHAT_MSG_BG_SYSTEM_HORDE, Source);
PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL, Source->GetName());
}
void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point)

View file

@ -23,9 +23,8 @@
class BattleGround;
#define EY_MAX_TEAM_SCORE 2000
#define BG_EY_FLAG_RESPAWN_TIME (10*IN_MILISECONDS) //10 seconds
#define BG_EY_FPOINTS_TICK_TIME (2*IN_MILISECONDS) //2 seconds
#define BG_EY_FLAG_RESPAWN_TIME (10*IN_MILISECONDS) //10 seconds
#define BG_EY_FPOINTS_TICK_TIME (2*IN_MILISECONDS) //2 seconds
enum BG_EY_WorldStates
{
@ -71,11 +70,11 @@ enum BG_EY_ProgressBarConsts
enum BG_EY_Sounds
{
//strange ids, but sure about them
BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212,
BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213,
BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174,
BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
BG_EY_SOUND_FLAG_RESET = 8192
BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212,
BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213,
BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174,
BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
BG_EY_SOUND_FLAG_RESET = 8192
};
enum BG_EY_Spells
@ -86,18 +85,18 @@ enum BG_EY_Spells
enum EYBattleGroundObjectEntry
{
BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door
BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door
BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic)
BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand)
BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop)
BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance)
BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde)
BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral)
BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt
BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt
BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt
BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt
BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door
BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door
BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic)
BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand)
BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop)
BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance)
BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde)
BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral)
BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt
BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt
BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt
BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt
};
enum EYBattleGroundPointsTrigger
@ -129,7 +128,7 @@ enum EYBattleGroundPoints
DRAENEI_RUINS = 2,
MAGE_TOWER = 3,
EY_PLAYERS_OUT_OF_POINTS = 4,
EY_PLAYERS_OUT_OF_POINTS = 4,
EY_POINTS_MAX = 4
};
@ -210,8 +209,14 @@ enum EYBattleGroundObjectTypes
BG_EY_OBJECT_MAX = 59
};
#define BG_EY_NotEYWeekendHonorTicks 330
#define BG_EY_EYWeekendHonorTicks 200
#define BG_EY_NotEYWeekendHonorTicks 330
#define BG_EY_EYWeekendHonorTicks 200
enum BG_EY_Score
{
BG_EY_WARNING_NEAR_VICTORY_SCORE = 1800,
BG_EY_MAX_TEAM_SCORE = 2000
};
enum BG_EY_FlagState
{

View file

@ -127,7 +127,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
if( !_player->CanJoinToBattleground() )
{
WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
data << (uint32) 0xFFFFFFFE;
data << uint32(0xFFFFFFFE);
_player->GetSession()->SendPacket(&data);
return;
}
@ -173,7 +173,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
WorldPacket data;
// send status packet (in queue)
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
member->GetSession()->SendPacket(&data);
sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
member->GetSession()->SendPacket(&data);
@ -191,7 +191,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
WorldPacket data;
// send status packet (in queue)
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
SendPacket(&data);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
@ -302,25 +302,25 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action;
if(!sBattlemasterListStore.LookupEntry(bgTypeId_))
if( !sBattlemasterListStore.LookupEntry(bgTypeId_) )
{
sLog.outError("Battleground: invalid bgtype (%u) received.",bgTypeId_);
sLog.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_);
// update battleground slots for the player to fix his UI and sent data.
// this is a HACK, I don't know why the client starts sending invalid packets in the first place.
// it usually happens with extremely high latency (if debugging / stepping in the code for example)
if(_player->InBattleGroundQueue())
if( _player->InBattleGroundQueue() )
{
// update all queues, send invitation info if player is invited, queue info if queued
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
{
BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
if(!bgQueueTypeId)
if( !bgQueueTypeId )
continue;
BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
// if the player is not in queue, continue or no group information - this should never happen
if(itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo)
if( itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo )
continue;
BattleGround * bg = NULL;
@ -329,7 +329,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated;
uint8 status = 0;
if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
if( !itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID )
{
// not invited to bg, get template
bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
@ -342,12 +342,8 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
status = STATUS_WAIT_JOIN;
}
// if bg not found, then continue
if(!bg)
continue;
// don't invite if already in the instance
if(_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID())
// if bg not found, then continue, don't invite if already in the instance
if( !bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()) )
continue;
// re - invite player with proper data
@ -359,22 +355,20 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
return;
}
//get GroupQueueInfo from BattleGroundQueue
BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
BattleGroundQueueTypeId bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
// get the bg what we were invited to
bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
if(itrPlayerStatus == qpMap.end())
if( itrPlayerStatus == qpMap.end() )
{
sLog.outError("Battleground: itrplayerstatus not found.");
return;
}
instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
// if action == 1, then instanceId is _required_
if(!instanceId && action == 1)
instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
// if action == 1, then instanceId is required
if( !instanceId && action == 1 )
{
sLog.outError("Battleground: instance not found.");
return;
@ -383,56 +377,52 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId);
// bg template might and must be used in case of leaving queue, when instance is not created yet
if(!bg && action == 0)
if( !bg && action == 0 )
bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
if(!bg)
if( !bg )
{
sLog.outError("Battleground: bg not found for type id %u.",bgTypeId);
sLog.outError("Battleground: bg_template not found for type id %u.", bgTypeId);
return;
}
bgTypeId = bg->GetTypeID();
if(_player->InBattleGroundQueue())
if( _player->InBattleGroundQueue() )
{
uint32 queueSlot = 0;
uint32 team = 0;
uint32 arenatype = 0;
uint32 israted = 0;
uint32 rating = 0;
uint32 opponentsRating = 0;
// get the team info from the queue
//we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function!
uint32 team = itrPlayerStatus->second.GroupInfo->Team;
uint32 arenaType = itrPlayerStatus->second.GroupInfo->ArenaType;
uint32 isRated = itrPlayerStatus->second.GroupInfo->IsRated;
uint32 rating = itrPlayerStatus->second.GroupInfo->ArenaTeamRating;
uint32 opponentsRating = itrPlayerStatus->second.GroupInfo->OpponentsTeamRating;
BattleGroundQueue::QueuedPlayersMap& qpMap2 = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap::iterator pitr = qpMap2.find(_player->GetGUID());
if (pitr !=qpMap2.end() && pitr->second.GroupInfo)
//some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
if( action == 1 && arenaType == 0)
{
team = pitr->second.GroupInfo->Team;
arenatype = pitr->second.GroupInfo->ArenaType;
israted = pitr->second.GroupInfo->IsRated;
rating = pitr->second.GroupInfo->ArenaTeamRating;
opponentsRating = pitr->second.GroupInfo->OpponentsTeamRating;
}
else
{
sLog.outError("Battleground: Invalid player queue info!");
return;
}
//if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
if( arenatype == 0 && !_player->CanJoinToBattleground() )
{
sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
action = 0;
//if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
if( !_player->CanJoinToBattleground() )
{
//send bg command result to show nice message
WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
data2 << uint32(0xFFFFFFFE);
_player->GetSession()->SendPacket(&data2);
action = 0;
sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
}
//if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue
if( _player->getLevel() > bg->GetMaxLevel() )
{
sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
action = 0;
}
}
uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
WorldPacket data;
switch(action)
switch( action )
{
case 1: // port to battleground
if(!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
return; // cheating?
case 1: // port to battleground
if( !_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId) )
return; // cheating?
// resurrect the player
if(!_player->isAlive())
if( !_player->isAlive() )
{
_player->ResurrectPlayer(1.0f);
_player->SpawnCorpseBones();
@ -443,14 +433,13 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
_player->GetMotionMaster()->MovementExpired();
_player->m_taxi.ClearTaxiDestinations();
}
_player->RemoveFromGroup();
queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
_player->GetSession()->SendPacket(&data);
// remove battleground queue status from BGmgr
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
// also this required to prevent stuck at old battleground after SetBattleGroundId set to new
// also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
if( BattleGround *currentBg = _player->GetBattleGround() )
currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
@ -462,30 +451,28 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId);
// add only in HandleMoveWorldPortAck()
// bg->AddPlayer(_player,team);
sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId);
sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId);
break;
case 0: // leave queue
queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
/*
if player leaves rated arena match before match start, it is counted as he played but he lost
*/
if (israted)
// if player leaves rated arena match before match start, it is counted as he played but he lost
if( isRated )
{
ArenaTeam * at = objmgr.GetArenaTeamById(team);
if (at)
if( at )
{
sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating);
at->MemberLost(_player, opponentsRating);
at->SaveToDB();
}
}
_player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0);
_player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
// player left queue, we should update it, maybe now his group fits in
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId,_player->GetBattleGroundQueueIdFromLevel(bgTypeId),arenatype,israted,rating);
// player left queue, we should update it - do not update Arena Queue
if( !arenaType )
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenaType, isRated, rating);
SendPacket(&data);
sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetTypeID(),bgQueueTypeId);
sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId);
break;
default:
sLog.outError("Battleground port: unknown action %u", action);
@ -524,40 +511,55 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
sLog.outDebug( "WORLD: Battleground status" );
WorldPacket data;
uint32 queueSlot = PLAYER_MAX_BATTLEGROUND_QUEUES;
if(_player->InBattleGround())
{
BattleGround *bg = _player->GetBattleGround();
if(!bg)
return;
BattleGroundQueueTypeId bgQueueTypeId_tmp = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId_tmp);
if((bg->GetStatus() <= STATUS_IN_PROGRESS))
{
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
SendPacket(&data);
}
}
// we should update all queues? .. i'm not sure if this code is correct
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
// we must update all queues here
BattleGround *bg = NULL;
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
{
BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
if(!bgQueueTypeId || i == queueSlot) //queueslot check in case we already send it in the above code
if( !bgQueueTypeId )
continue;
BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId);
BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
if(!bg)
continue;
uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId);
if( bgTypeId == _player->GetBattleGroundTypeId() )
{
bg = _player->GetBattleGround();
//i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
//so i must use bg pointer to get that information
if( bg && bg->GetArenaType() == arenaType )
{
// this line is checked, i only don't know if GetStartTime is changing itself after bg end!
// send status in BattleGround
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType);
SendPacket(&data);
continue;
}
}
//we are sending update to player about queue - he can be invited there!
//get GroupQueueInfo for queue status
BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
if(itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo)
if( itrPlayerStatus == qpMap.end() )
continue;
arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTime()-itrPlayerStatus->second.GroupInfo->JoinTime, arenatype);
SendPacket(&data);
if( itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID )
{
bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
if( !bg )
continue;
uint32 remainingTime = getMSTimeDiff(getMSTime(), itrPlayerStatus->second.GroupInfo->RemoveInviteTime);
// send status invited to BattleGround
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType);
SendPacket(&data);
}
else
{
BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
if( !bg )
continue;
uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
// send status in BattleGround Queue
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(itrPlayerStatus->second.GroupInfo->JoinTime, getMSTime()), arenaType);
SendPacket(&data);
}
}
}

View file

@ -159,7 +159,8 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId
ginfo->ArenaTeamId = arenateamid;
ginfo->IsRated = isRated;
ginfo->IsInvitedToBGInstanceGUID = 0;
ginfo->JoinTime = sWorld.GetGameTime() * IN_MILISECONDS;
ginfo->JoinTime = getMSTime();
ginfo->RemoveInviteTime = 0;
ginfo->Team = leader->GetTeam();
ginfo->ArenaTeamRating = arenaRating;
ginfo->OpponentsTeamRating = 0;
@ -194,7 +195,7 @@ void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
{
uint32 timeInQueue = (sWorld.GetGameTime() * IN_MILISECONDS) - ginfo->JoinTime;
uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime());
uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
if( !ginfo->ArenaType )
{
@ -353,7 +354,7 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou
plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to
// queue->removeplayer, it causes bugs
WorldPacket data;
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
plr2->GetSession()->SendPacket(&data);
}
// then actually delete, this may delete the group as well!
@ -442,6 +443,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b
// invite the player
PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id);
ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME;
sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(), bg->GetTypeID(), ginfo->Team);
WorldPacket data;
@ -451,7 +453,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b
sLog.outDebug("Battleground: invited plr %s (%u) to BG instance %u queueindex %u bgtype %u, I can't help it if they don't press the enter battle button.",plr->GetName(),plr->GetGUIDLow(),bg->GetInstanceID(),queueSlot,bg->GetTypeID());
// send status packet
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType);
plr->GetSession()->SendPacket(&data);
}
return true;
@ -508,7 +510,7 @@ void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
// remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
RemovePlayer(itr2->first, true);
WorldPacket data;
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
plr->GetSession()->SendPacket(&data);
}
}
@ -1067,7 +1069,8 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
{
WorldPacket data;
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITATION_REMIND_TIME, 0);
//here must be remaining time
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType);
plr->GetSession()->SendPacket(&data);
}
}
@ -1106,7 +1109,7 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(), bg->GetQueueId());
WorldPacket data;
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0);
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
plr->GetSession()->SendPacket(&data);
}
}
@ -1226,7 +1229,7 @@ void BattleGroundMgr::Update(uint32 diff)
}
}
void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype)
void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
{
// we can be in 3 queues in same time...
if(StatusID == 0)
@ -1240,11 +1243,11 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
*data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
// uint64 in client
*data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
*data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
*data << uint32(bg->GetClientInstanceID());
// alliance/horde for BG and skirmish/rated for Arenas
// following displays the minimap-icon 0 = faction icon 1 = arenaicon
*data << uint8(bg->isArena());
*data << uint8(bg->isRated());
/* *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!!
switch(bg->GetTypeID()) // value depends on bg id
{
@ -1301,7 +1304,7 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
{
case STATUS_WAIT_QUEUE: // status_in_queue
*data << uint32(Time1); // average wait time, milliseconds
*data << uint32(Time2); // time in queue, updated every minute?
*data << uint32(Time2); // time in queue, updated every minute!, milliseconds
break;
case STATUS_WAIT_JOIN: // status_invite
*data << uint32(bg->GetMapId()); // map id
@ -1309,7 +1312,7 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
break;
case STATUS_IN_PROGRESS: // status_in_progress
*data << uint32(bg->GetMapId()); // map id
*data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
*data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
*data << uint32(Time2); // time from bg start, milliseconds
*data << uint8(0x1); // unk sometimes 0x0!
break;

View file

@ -48,6 +48,7 @@ struct GroupQueueInfo // stores informatio
uint8 ArenaType; // 2v2, 3v3, 5v5 or 0 when BG
uint32 ArenaTeamId; // team id if rated match
uint32 JoinTime; // time when group was added
uint32 RemoveInviteTime; // time when we will remove invite for players in group
uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG
uint32 ArenaTeamRating; // if rated match, inited to the rating of the team
uint32 OpponentsTeamRating; // for rated arena matches
@ -184,7 +185,7 @@ class BattleGroundMgr
void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId);
void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value);
void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg);
void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0);
void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype);
void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid);
void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid);

View file

@ -34,6 +34,8 @@
#include "SpellAuras.h"
#include "Language.h"
#include "Util.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
{
@ -232,13 +234,15 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
Group *group = GetPlayer()->GetGroup();
if(!group)
// if player is in battleground, he cannot say to battleground members by /p
Group *group = GetPlayer()->GetOriginalGroup();
// so if player hasn't OriginalGroup and his player->GetGroup() is BG raid, then return
if( !group && (!(group = GetPlayer()->GetGroup()) || group->isBGGroup()) )
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_PARTY, lang, NULL, 0, msg.c_str(),NULL);
group->BroadcastPacket(&data, group->GetMemberGroup(GetPlayer()->GetGUID()));
group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID()));
}
break;
case CHAT_MSG_GUILD:
@ -312,13 +316,15 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
Group *group = GetPlayer()->GetGroup();
if(!group || !group->isRaidGroup())
// if player is in battleground, he cannot say to battleground members by /ra
Group *group = GetPlayer()->GetOriginalGroup();
// so if player hasn't OriginalGroup and his player->GetGroup() is BG raid or his group isn't raid, then return
if( !group && !(group = GetPlayer()->GetGroup()) || group->isBGGroup() || !group->isRaidGroup() )
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL);
group->BroadcastPacket(&data);
group->BroadcastPacket(&data, false);
} break;
case CHAT_MSG_RAID_LEADER:
{
@ -338,13 +344,14 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
Group *group = GetPlayer()->GetGroup();
if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
// if player is in battleground, he cannot say to battleground members by /ra
Group *group = GetPlayer()->GetOriginalGroup();
if( !group && !(group = GetPlayer()->GetGroup()) || group->isBGGroup() || !group->isRaidGroup() )
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(),NULL);
group->BroadcastPacket(&data);
group->BroadcastPacket(&data, false);
} break;
case CHAT_MSG_RAID_WARNING:
{
@ -363,8 +370,9 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
return;
WorldPacket data;
//in battleground, raid warning is sent only to players in battleground - code is ok
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(),NULL);
group->BroadcastPacket(&data);
group->BroadcastPacket(&data, false);
} break;
case CHAT_MSG_BATTLEGROUND:
@ -379,13 +387,14 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
//battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
Group *group = GetPlayer()->GetGroup();
if(!group || !group->isRaidGroup())
if(!group || !group->isBGGroup())
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(),NULL);
group->BroadcastPacket(&data);
group->BroadcastPacket(&data, false);
} break;
case CHAT_MSG_BATTLEGROUND_LEADER:
@ -400,13 +409,14 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
//battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
Group *group = GetPlayer()->GetGroup();
if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
if(!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(),NULL);
group->BroadcastPacket(&data);
group->BroadcastPacket(&data, false);
} break;
case CHAT_MSG_CHANNEL:
@ -488,6 +498,38 @@ void WorldSession::HandleEmoteOpcode( WorldPacket & recv_data )
GetPlayer()->HandleEmoteCommand(emote);
}
namespace MaNGOS
{
class EmoteChatBuilder
{
public:
EmoteChatBuilder(Player const& pl, uint32 text_emote, uint32 emote_num, Unit const* target)
: i_player(pl), i_text_emote(text_emote), i_emote_num(emote_num), i_target(target) {}
void operator()(WorldPacket& data, int32 loc_idx)
{
char const* nam = i_target ? i_target->GetNameForLocaleIdx(loc_idx) : NULL;
uint32 namlen = (nam ? strlen(nam) : 0) + 1;
data.Initialize(SMSG_TEXT_EMOTE, (20+namlen));
data << i_player.GetGUID();
data << (uint32)i_text_emote;
data << i_emote_num;
data << (uint32)namlen;
if( namlen > 1 )
data.append(nam, namlen);
else
data << (uint8)0x00;
}
private:
Player const& i_player;
uint32 i_text_emote;
uint32 i_emote_num;
Unit const* i_target;
};
} // namespace MaNGOS
void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
{
if(!GetPlayer()->isAlive())
@ -509,27 +551,12 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
recv_data >> emoteNum;
recv_data >> guid;
const char *nam = 0;
uint32 namlen = 1;
Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
Creature *pCreature = dynamic_cast<Creature *>(unit);
if(unit)
{
nam = unit->GetName();
namlen = (nam ? strlen(nam) : 0) + 1;
}
EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote);
if (!em)
return;
GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit);
uint32 emote_anim = em->textid;
WorldPacket data;
switch(emote_anim)
{
case EMOTE_STATE_SLEEP:
@ -542,21 +569,26 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
break;
}
data.Initialize(SMSG_TEXT_EMOTE, (20+namlen));
data << GetPlayer()->GetGUID();
data << (uint32)text_emote;
data << emoteNum;
data << (uint32)namlen;
if( namlen > 1 )
data.append(nam, namlen);
else
data << (uint8)0x00;
Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
CellPair p = MaNGOS::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
MaNGOS::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit);
MaNGOS::LocalizedPacketDo<MaNGOS::EmoteChatBuilder > emote_do(emote_builder);
MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::EmoteChatBuilder > > emote_worker(GetPlayer(),sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),emote_do);
TypeContainerVisitor<MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::EmoteChatBuilder > >, WorldTypeMapContainer > message(emote_worker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *GetPlayer()->GetMap());
GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit);
//Send scripted event call
if (pCreature && Script)
Script->ReceiveEmote(GetPlayer(),pCreature,text_emote);
if (unit && unit->GetTypeId()==TYPEID_UNIT && Script)
Script->ReceiveEmote(GetPlayer(),(Creature*)unit,text_emote);
}
void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data )

View file

@ -201,7 +201,8 @@ void Group::ConvertToRaid()
_initRaidSubGroupsCounter();
if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
if(!isBGGroup())
CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
SendUpdate();
// update quest related GO states (quest activity dependent from raid membership)
@ -212,7 +213,12 @@ void Group::ConvertToRaid()
bool Group::AddInvite(Player *player)
{
if(!player || player->GetGroupInvite() || player->GetGroup())
if( !player || player->GetGroupInvite() )
return false;
Group* group = player->GetGroup();
if( group && group->isBGGroup() )
group = player->GetOriginalGroup();
if( group )
return false;
RemoveInvite(player);
@ -323,9 +329,17 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
player->GetSession()->SendPacket( &data );
}
data.Initialize(SMSG_GROUP_LIST, 24);
data << uint64(0) << uint64(0) << uint64(0);
player->GetSession()->SendPacket(&data);
//we already removed player from group and in player->GetGroup() is his original group!
if( Group* group = player->GetGroup() )
{
group->SendUpdate();
}
else
{
data.Initialize(SMSG_GROUP_LIST, 24);
data << uint64(0) << uint64(0) << uint64(0);
player->GetSession()->SendPacket(&data);
}
_homebindIfInstance(player);
}
@ -334,7 +348,7 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
{
WorldPacket data(SMSG_GROUP_SET_LEADER, (m_memberSlots.front().name.size()+1));
data << m_memberSlots.front().name;
BroadcastPacket(&data);
BroadcastPacket(&data, true);
}
SendUpdate();
@ -357,7 +371,7 @@ void Group::ChangeLeader(const uint64 &guid)
WorldPacket data(SMSG_GROUP_SET_LEADER, slot->name.size()+1);
data << slot->name;
BroadcastPacket(&data);
BroadcastPacket(&data, true);
SendUpdate();
}
@ -371,13 +385,23 @@ void Group::Disband(bool hideDestroy)
if(!player)
continue;
player->SetGroup(NULL);
//we cannot call _removeMember because it would invalidate member iterator
//if we are removing player from battleground raid
if( isBGGroup() )
player->RemoveFromBattleGroundRaid();
else
{
//we can remove player who is in battleground from his original group
if( player->GetOriginalGroup() == this )
player->SetOriginalGroup(NULL);
else
player->SetGroup(NULL);
}
// quest related GO state dependent from raid membership
if(isRaidGroup())
player->UpdateForQuestsGO();
if(!player->GetSession())
continue;
@ -388,9 +412,17 @@ void Group::Disband(bool hideDestroy)
player->GetSession()->SendPacket(&data);
}
data.Initialize(SMSG_GROUP_LIST, 24);
data << uint64(0) << uint64(0) << uint64(0);
player->GetSession()->SendPacket(&data);
//we already removed player from group and in player->GetGroup() is his original group, send update
if( Group* group = player->GetGroup() )
{
group->SendUpdate();
}
else
{
data.Initialize(SMSG_GROUP_LIST, 24);
data << uint64(0) << uint64(0) << uint64(0);
player->GetSession()->SendPacket(&data);
}
_homebindIfInstance(player);
}
@ -838,7 +870,7 @@ void Group::SetTargetIcon(uint8 id, uint64 guid)
data << (uint8)0;
data << id;
data << guid;
BroadcastPacket(&data);
BroadcastPacket(&data, true);
}
void Group::GetDataForXPAtKill(Unit const* victim, uint32& count,uint32& sum_level, Player* & member_with_max_level, Player* & not_gray_member_with_max_level)
@ -891,7 +923,7 @@ void Group::SendUpdate()
for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
{
player = objmgr.GetPlayer(citr->guid);
if(!player || !player->GetSession())
if(!player || !player->GetSession() || player->GetGroup() != this )
continue;
// guess size
WorldPacket data(SMSG_GROUP_LIST, (1+1+1+1+8+4+GetMembersCount()*20));
@ -905,11 +937,14 @@ void Group::SendUpdate()
{
if(citr->guid == citr2->guid)
continue;
Player* member = objmgr.GetPlayer(citr2->guid);
uint8 onlineState = (member) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE;
onlineState = onlineState | ((isBGGroup()) ? MEMBER_STATUS_PVP : 0);
data << citr2->name;
data << (uint64)citr2->guid;
// online-state
data << (uint8)(objmgr.GetPlayer(citr2->guid) ? 1 : 0);
data << (uint8)(onlineState);
data << (uint8)(citr2->group); // groupid
data << (uint8)(citr2->assistant?0x01:0); // 0x2 main assist, 0x4 main tank
}
@ -943,12 +978,12 @@ void Group::UpdatePlayerOutOfRange(Player* pPlayer)
}
}
void Group::BroadcastPacket(WorldPacket *packet, int group, uint64 ignore)
void Group::BroadcastPacket(WorldPacket *packet, bool ignorePlayersInBGRaid, int group, uint64 ignore)
{
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *pl = itr->getSource();
if(!pl || (ignore != 0 && pl->GetGUID() == ignore))
if(!pl || (ignore != 0 && pl->GetGUID() == ignore) || (ignorePlayersInBGRaid && pl->GetGroup() != this) )
continue;
if (pl->GetSession() && (group==-1 || itr->getSubGroup()==group))
@ -1027,7 +1062,15 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, u
if(player)
{
player->SetGroupInvite(NULL);
player->SetGroup(this, group);
//if player is in group and he is being added to BG raid group, then call SetBattleGroundRaid()
if( player->GetGroup() && isBGGroup() )
player->SetBattleGroundRaid(this, group);
//if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup()
else if ( player->GetGroup() )
player->SetOriginalGroup(this, group);
//if player is not in group, then call set group
else
player->SetGroup(this, group);
// if the same group invites the player back, cancel the homebind timer
InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player->GetDifficulty());
if(bind && bind->save->GetInstanceId() == player->GetInstanceId())
@ -1054,7 +1097,17 @@ bool Group::_removeMember(const uint64 &guid)
Player *player = objmgr.GetPlayer(guid);
if (player)
{
player->SetGroup(NULL);
//if we are removing player from battleground raid
if( isBGGroup() )
player->RemoveFromBattleGroundRaid();
else
{
//we can remove player who is in battleground from his original group
if( player->GetOriginalGroup() == this )
player->SetOriginalGroup(NULL);
else
player->SetGroup(NULL);
}
}
_removeRolls(guid);
@ -1246,12 +1299,17 @@ void Group::ChangeMembersGroup(Player *player, const uint8 &group)
return;
if(_setMembersGroup(player->GetGUID(), group))
{
uint8 prevSubGroup;
prevSubGroup = player->GetSubGroup();
uint8 prevSubGroup = player->GetSubGroup();
if( player->GetGroup() == this )
player->GetGroupRef().setSubGroup(group);
//if player is in BG raid, it is possible that he is also in normal raid - and that normal raid is stored in m_originalGroup reference
else
{
prevSubGroup = player->GetOriginalSubGroup();
player->GetOriginalGroupRef().setSubGroup(group);
}
SubGroupCounterDecrease(prevSubGroup);
player->GetGroupRef().setSubGroup(group);
SendUpdate();
}
}

View file

@ -291,7 +291,7 @@ class MANGOS_DLL_SPEC Group
void SendUpdate();
void UpdatePlayerOutOfRange(Player* pPlayer);
// ignore: GUID of player that will be ignored
void BroadcastPacket(WorldPacket *packet, int group=-1, uint64 ignore=0);
void BroadcastPacket(WorldPacket *packet, bool ignorePlayersInBGRaid, int group=-1, uint64 ignore=0);
void BroadcastReadyCheck(WorldPacket *packet);
void OfflineReadyCheck();

View file

@ -55,12 +55,6 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
std::string membername;
recv_data >> membername;
if(_player->InBattleGround())
{
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_INVITE_RESTRICTED);
return;
}
// attempt add selected player
// cheating
@ -97,15 +91,20 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
return;
}
Group *group = GetPlayer()->GetGroup();
if( group && group->isBGGroup() )
group = GetPlayer()->GetOriginalGroup();
Group *group2 = player->GetGroup();
if( group2 && group2->isBGGroup() )
group2 = player->GetOriginalGroup();
// player already in another group or invited
if(player->GetGroup() || player->GetGroupInvite() )
if( group2 || player->GetGroupInvite() )
{
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_ALREADY_IN_GROUP);
return;
}
Group *group = GetPlayer()->GetGroup();
if(group)
{
// not have permissions for invite
@ -114,7 +113,6 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_YOU_NOT_LEADER);
return;
}
// not have place
if(group->IsFull())
{
@ -185,27 +183,20 @@ void WorldSession::HandleGroupAcceptOpcode( WorldPacket & /*recv_data*/ )
Player* leader = objmgr.GetPlayer(group->GetLeaderGUID());
if(leader && leader->InBattleGround())
{
SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_INVITE_RESTRICTED);
return;
}
// forming a new group, create it
if(!group->IsCreated())
{
if(leader) group->RemoveInvite(leader);
if( leader )
group->RemoveInvite(leader);
group->Create(group->GetLeaderGUID(), group->GetLeaderName());
objmgr.AddGroup(group);
}
// everything's fine, do it
// everything's fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!!
if(!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName()))
return;
uint8 subgroup = group->GetMemberGroup(GetPlayer()->GetGUID());
GetPlayer()->SetGroup(group, subgroup);
}
void WorldSession::HandleGroupDeclineOpcode( WorldPacket & /*recv_data*/ )
@ -424,7 +415,7 @@ void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data)
data << GetPlayer()->GetGUID();
data << x;
data << y;
GetPlayer()->GetGroup()->BroadcastPacket(&data, -1, GetPlayer()->GetGUID());
GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID());
}
void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data)
@ -451,7 +442,7 @@ void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data)
data << roll;
data << GetPlayer()->GetGUID();
if(GetPlayer()->GetGroup())
GetPlayer()->GetGroup()->BroadcastPacket(&data);
GetPlayer()->GetGroup()->BroadcastPacket(&data, false);
else
SendPacket(&data);
}
@ -512,6 +503,7 @@ void WorldSession::HandleGroupChangeSubGroupOpcode( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data,1+1);
// we will get correct pointer for group here, so we don't have to check if group is BG raid
Group *group = GetPlayer()->GetGroup();
if(!group)
return;
@ -604,7 +596,7 @@ void WorldSession::HandleRaidReadyCheckOpcode( WorldPacket & recv_data )
// everything's fine, do it
WorldPacket data(MSG_RAID_READY_CHECK, 8);
data << GetPlayer()->GetGUID();
group->BroadcastPacket(&data, -1);
group->BroadcastPacket(&data, false, -1);
group->OfflineReadyCheck();
}

View file

@ -285,13 +285,10 @@ class MANGOS_DLL_SPEC Item : public Object
uState = state;
}
bool hasQuest(uint32 quest_id) const
{
ItemPrototype const *itemProto = GetProto();
return itemProto && itemProto->StartQuest == quest_id;
}
bool hasQuest(uint32 quest_id) const { return GetProto()->StartQuest == quest_id; }
bool hasInvolvedQuest(uint32 /*quest_id*/) const { return false; }
bool IsPotion() const { return GetProto()->IsPotion(); }
bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); }
private:
uint8 m_slot;
Bag *m_container;

View file

@ -656,6 +656,9 @@ struct ItemPrototype
}
return 0;
}
bool IsPotion() const { return Class==ITEM_CLASS_CONSUMABLE && SubClass==ITEM_SUBCLASS_POTION; }
bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_FLAGS_CONJURED); }
};
struct ItemLocale

View file

@ -692,9 +692,9 @@ enum MangosStrings
LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 750, // "Not enough players. This game will close in %u mins."
LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS = 751, // "Not enough players. This game will close in %u seconds."
// = 752, not used
// LANG_BG_WS_START_TWO_MINUTES = 753,
// LANG_BG_AB_START_TWO_MINUTES = 754,
// LANG_BG_EY_START_TWO_MINUTES = 755,
// LANG_BG_WS_START_TWO_MINUTES = 753, - defined above
// LANG_BG_AB_START_TWO_MINUTES = 754, - defined above
// LANG_BG_EY_START_TWO_MINUTES = 755, - defined above
// Room for batleground/arena strings 756-799 not used
// in game strings

View file

@ -65,7 +65,8 @@ bool Map::ExistMap(uint32 mapid,int x,int y)
map_fileheader header;
fread(&header, sizeof(header), 1, pf);
if (header.mapMagic != MAP_MAGIC || header.versionMagic != MAP_VERSION_MAGIC)
if (header.mapMagic != uint32(MAP_MAGIC) ||
header.versionMagic != uint32(MAP_VERSION_MAGIC))
{
sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp);
delete [] tmp;
@ -1081,7 +1082,8 @@ bool GridMap::loadData(char *filename)
if (!in)
return true;
fread(&header, sizeof(header),1,in);
if (header.mapMagic == MAP_MAGIC && header.versionMagic == MAP_VERSION_MAGIC)
if (header.mapMagic == uint32(MAP_MAGIC) &&
header.versionMagic == uint32(MAP_VERSION_MAGIC))
{
// loadup area data
if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize))
@ -1132,11 +1134,11 @@ bool GridMap::loadAreaData(FILE *in, uint32 offset, uint32 size)
map_areaHeader header;
fseek(in, offset, SEEK_SET);
fread(&header, sizeof(header), 1, in);
if (header.fourcc != MAP_AREA_MAGIC)
if (header.fourcc != uint32(MAP_AREA_MAGIC))
return false;
m_gridArea = header.gridArea;
if (!(header.flags&MAP_AREA_NO_AREA))
if (!(header.flags & MAP_AREA_NO_AREA))
{
m_area_map = new uint16 [16*16];
fread(m_area_map, sizeof(uint16), 16*16, in);
@ -1149,13 +1151,13 @@ bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size)
map_heightHeader header;
fseek(in, offset, SEEK_SET);
fread(&header, sizeof(header), 1, in);
if (header.fourcc != MAP_HEIGTH_MAGIC)
if (header.fourcc != uint32(MAP_HEIGTH_MAGIC))
return false;
m_gridHeight = header.gridHeight;
if (!(header.flags&MAP_HEIGHT_NO_HIGHT))
if (!(header.flags & MAP_HEIGHT_NO_HIGHT))
{
if ((header.flags&MAP_HEIGHT_AS_INT16))
if ((header.flags & MAP_HEIGHT_AS_INT16))
{
m_uint16_V9 = new uint16 [129*129];
m_uint16_V8 = new uint16 [128*128];
@ -1164,7 +1166,7 @@ bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size)
m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535;
m_gridGetHeight = &GridMap::getHeightFromUint16;
}
else if ((header.flags&MAP_HEIGHT_AS_INT8))
else if ((header.flags & MAP_HEIGHT_AS_INT8))
{
m_uint8_V9 = new uint8 [129*129];
m_uint8_V8 = new uint8 [128*128];
@ -1192,7 +1194,7 @@ bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 size)
map_liquidHeader header;
fseek(in, offset, SEEK_SET);
fread(&header, sizeof(header), 1, in);
if (header.fourcc != MAP_LIQUID_MAGIC)
if (header.fourcc != uint32(MAP_LIQUID_MAGIC))
return false;
m_liquidType = header.liquidType;
@ -1529,7 +1531,7 @@ inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 R
}
// For speed check as int values
int delta = (liquid_level - z) * 10;
int delta = int((liquid_level - z) * 10);
// Get position delta
if (delta > 20) // Under water

View file

@ -43,8 +43,8 @@ MotionMaster::Initialize()
while(!empty())
{
MovementGenerator *curr = top();
curr->Finalize(*i_owner);
pop();
curr->Finalize(*i_owner);
if( !isStatic( curr ) )
delete curr;
}
@ -66,8 +66,8 @@ MotionMaster::~MotionMaster()
while(!empty())
{
MovementGenerator *curr = top();
curr->Finalize(*i_owner);
pop();
curr->Finalize(*i_owner);
if( !isStatic( curr ) )
delete curr;
}
@ -117,8 +117,8 @@ MotionMaster::DirectClean(bool reset)
while( !empty() && size() > 1 )
{
MovementGenerator *curr = top();
curr->Finalize(*i_owner);
pop();
curr->Finalize(*i_owner);
if( !isStatic( curr ) )
delete curr;
}
@ -142,8 +142,8 @@ MotionMaster::DelayedClean()
while( !empty() && size() > 1 )
{
MovementGenerator *curr = top();
curr->Finalize(*i_owner);
pop();
curr->Finalize(*i_owner);
if( !isStatic( curr ) )
m_expList->push_back(curr);
}
@ -156,23 +156,26 @@ MotionMaster::DirectExpire(bool reset)
return;
MovementGenerator *curr = top();
curr->Finalize(*i_owner);
pop();
// also drop stored under top() targeted motions
while( !empty() && top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE )
{
MovementGenerator *temp = top();
pop();
temp ->Finalize(*i_owner);
delete temp;
}
// it can add another motions instead
curr->Finalize(*i_owner);
if( !isStatic(curr) )
delete curr;
assert( !empty() );
while( !empty() && top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE )
{
// Should check if target is still valid? If not valid it will crash.
curr = top();
curr->Finalize(*i_owner);
pop();
delete curr;
}
if( empty() )
Initialize();
if (reset) top()->Reset(*i_owner);
}
@ -183,23 +186,24 @@ MotionMaster::DelayedExpire()
return;
MovementGenerator *curr = top();
curr->Finalize(*i_owner);
pop();
if(!m_expList)
m_expList = new ExpireList();
if( !isStatic(curr) )
m_expList->push_back(curr);
// also drop stored under top() targeted motions
while( !empty() && top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE )
{
// Should check if target is still valid? If not valid it will crash.
curr = top();
curr->Finalize(*i_owner);
MovementGenerator *temp = top();
pop();
m_expList->push_back(curr);
temp ->Finalize(*i_owner);
m_expList->push_back(temp );
}
curr->Finalize(*i_owner);
if( !isStatic(curr) )
m_expList->push_back(curr);
}
void MotionMaster::MoveIdle()

View file

@ -294,7 +294,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool
AIM_Initialize();
map->Add((Creature*)this);
// Spells should be loaded after pet is added to map, because in CanCast is check on it
// Spells should be loaded after pet is added to map, because in CheckCast is check on it
_LoadSpells();
_LoadSpellCooldowns();

View file

@ -189,7 +189,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
Spell *spell = new Spell(pet, spellInfo, false);
int16 result = spell->PetCanCast(unit_target);
SpellCastResult result = spell->CheckPetCast(unit_target);
//auto turn to target unless possessed
if(result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
@ -200,10 +200,10 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
if(Unit* powner = pet->GetCharmerOrOwner())
if(powner->GetTypeId() == TYPEID_PLAYER)
pet->SendUpdateToPlayer((Player*)powner);
result = -1;
result = SPELL_CAST_OK;
}
if(result == -1)
if(result == SPELL_CAST_OK)
{
((Creature*)pet)->AddCreatureSpellCooldown(spellid);
if (((Creature*)pet)->isPet())
@ -611,8 +611,8 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
spell->m_cast_count = cast_count; // probably pending spell cast
spell->m_targets = targets;
int16 result = spell->PetCanCast(NULL);
if(result == -1)
SpellCastResult result = spell->CheckPetCast(NULL);
if(result == SPELL_CAST_OK)
{
pet->AddCreatureSpellCooldown(spellid);
if(pet->isPet())

View file

@ -750,9 +750,9 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
}
// if this is ammo then use it
uint8 msg = CanUseAmmo( pItem->GetProto()->ItemId );
uint8 msg = CanUseAmmo( pItem->GetEntry() );
if( msg == EQUIP_ERR_OK )
SetAmmo( pItem->GetProto()->ItemId );
SetAmmo( pItem->GetEntry() );
}
}
}
@ -2891,8 +2891,8 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
continue;
if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ||
// lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 )
// lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
(pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0 )
{
switch(GetSkillRangeType(pSkill,_spell_idx->second->racemask!=0))
{
@ -2929,8 +2929,8 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
if(IsInWorld())
{
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL,spell_id);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS,spell_id);
}
// return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell
@ -3101,8 +3101,8 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
continue;
if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ||
// lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 )
// lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
(pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0 )
{
// not reset skills for professions and racial abilities
if( (pSkill->categoryId==SKILL_CATEGORY_SECONDARY || pSkill->categoryId==SKILL_CATEGORY_PROFESSION) &&
@ -4029,7 +4029,7 @@ void Player::CreateCorpse()
flags |= CORPSE_FLAG_HIDE_HELM;
if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
flags |= CORPSE_FLAG_HIDE_CLOAK;
if(InBattleGround())
if(InBattleGround() && !InArena())
flags |= CORPSE_FLAG_LOOTABLE; // to be able to remove insignia
corpse->SetUInt32Value( CORPSE_FIELD_FLAGS, flags );
@ -5344,12 +5344,12 @@ void Player::SendInitialActionButtons()
sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
}
void Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc)
bool Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc)
{
if(button >= MAX_ACTION_BUTTONS)
{
sLog.outError( "Action %u not added into button %u for player %s: button must be < 132", action, button, GetName() );
return;
return false;
}
// check cheating with adding non-known spells to action bar
@ -5358,13 +5358,13 @@ void Player::addActionButton(const uint8 button, const uint16 action, const uint
if(!sSpellStore.LookupEntry(action))
{
sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() );
return;
return false;
}
if(!HasSpell(action))
{
sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() );
return;
return false;
}
}
@ -5382,6 +5382,7 @@ void Player::addActionButton(const uint8 button, const uint16 action, const uint
};
sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button );
return true;
}
void Player::removeActionButton(uint8 button)
@ -5934,8 +5935,8 @@ bool Player::ModifyOneFactionReputation(FactionEntry const* factionEntry, int32
}
}
}
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION,factionEntry->ID);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION,factionEntry->ID);
SendFactionState(&(itr->second));
return true;
@ -6001,8 +6002,8 @@ bool Player::SetOneFactionReputation(FactionEntry const* factionEntry, int32 sta
SetFactionAtWar(&itr->second,true);
SendFactionState(&(itr->second));
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION,factionEntry->ID);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION,factionEntry->ID);
return true;
}
return false;
@ -7004,7 +7005,7 @@ void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply
if(apply)
{
// Cannot be used in this stance/form
if(GetErrorAtShapeshiftedCast(spellInfo, m_form)!=0)
if(GetErrorAtShapeshiftedCast(spellInfo, m_form) != SPELL_CAST_OK)
return;
if(form_change) // check aura active state from other form
@ -7038,7 +7039,7 @@ void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply
if(form_change) // check aura compatibility
{
// Cannot be used in this stance/form
if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==0)
if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==SPELL_CAST_OK)
return; // and remove only not compatible at form change
}
@ -7450,6 +7451,9 @@ void Player::SendLootRelease( uint64 guid )
void Player::SendLoot(uint64 guid, LootType loot_type)
{
if (uint64 lguid = GetLootGUID())
m_session->DoLootRelease(lguid);
Loot *loot = 0;
PermissionTypes permission = ALL_PERMISSION;
@ -10667,6 +10671,8 @@ Item* Player::EquipItem( uint16 pos, Item *pItem, bool update )
}
}
// only for full equip instead adding to stack
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry());
return pItem;
}
@ -10913,60 +10919,60 @@ void Player::DestroyItem( uint8 bag, uint8 slot, bool update )
void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check)
{
sLog.outDebug( "STORAGE: DestroyItemCount item = %u, count = %u", item, count);
Item *pItem;
ItemPrototype const *pProto;
uint32 remcount = 0;
// in inventory
for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
{
pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->GetEntry() == item )
if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
{
if( pItem->GetCount() + remcount <= count )
if (pItem->GetEntry() == item)
{
// all items in inventory can unequipped
remcount += pItem->GetCount();
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
if (pItem->GetCount() + remcount <= count)
{
// all items in inventory can unequipped
remcount += pItem->GetCount();
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
if(remcount >=count)
if (remcount >=count)
return;
}
else
{
ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
pItem->SetCount( pItem->GetCount() - count + remcount );
if (IsInWorld() & update)
pItem->SendUpdateToPlayer( this );
pItem->SetState(ITEM_CHANGED, this);
return;
}
else
{
pProto = pItem->GetProto();
ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
pItem->SetCount( pItem->GetCount() - count + remcount );
if( IsInWorld() & update )
pItem->SendUpdateToPlayer( this );
pItem->SetState(ITEM_CHANGED, this);
return;
}
}
}
}
for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
{
pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->GetEntry() == item )
if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
{
if( pItem->GetCount() + remcount <= count )
if (pItem->GetEntry() == item)
{
// all keys can be unequipped
remcount += pItem->GetCount();
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
if (pItem->GetCount() + remcount <= count)
{
// all keys can be unequipped
remcount += pItem->GetCount();
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
if(remcount >=count)
if (remcount >=count)
return;
}
else
{
ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
pItem->SetCount( pItem->GetCount() - count + remcount );
if (IsInWorld() & update)
pItem->SendUpdateToPlayer( this );
pItem->SetState(ITEM_CHANGED, this);
return;
}
else
{
pProto = pItem->GetProto();
ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
pItem->SetCount( pItem->GetCount() - count + remcount );
if( IsInWorld() & update )
pItem->SendUpdateToPlayer( this );
pItem->SetState(ITEM_CHANGED, this);
return;
}
}
}
}
@ -10978,27 +10984,28 @@ void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool uneq
{
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
{
pItem = pBag->GetItemByPos(j);
if( pItem && pItem->GetEntry() == item )
if(Item* pItem = pBag->GetItemByPos(j))
{
// all items in bags can be unequipped
if( pItem->GetCount() + remcount <= count )
if (pItem->GetEntry() == item)
{
remcount += pItem->GetCount();
DestroyItem( i, j, update );
// all items in bags can be unequipped
if (pItem->GetCount() + remcount <= count)
{
remcount += pItem->GetCount();
DestroyItem( i, j, update );
if(remcount >=count)
if (remcount >=count)
return;
}
else
{
ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
pItem->SetCount( pItem->GetCount() - count + remcount );
if (IsInWorld() && update)
pItem->SendUpdateToPlayer( this );
pItem->SetState(ITEM_CHANGED, this);
return;
}
else
{
pProto = pItem->GetProto();
ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
pItem->SetCount( pItem->GetCount() - count + remcount );
if( IsInWorld() && update )
pItem->SendUpdateToPlayer( this );
pItem->SetState(ITEM_CHANGED, this);
return;
}
}
}
}
@ -11008,29 +11015,30 @@ void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool uneq
// in equipment and bag list
for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)
{
pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->GetEntry() == item )
if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
{
if( pItem->GetCount() + remcount <= count )
if (pItem && pItem->GetEntry() == item)
{
if(!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i,false) == EQUIP_ERR_OK )
if (pItem->GetCount() + remcount <= count)
{
remcount += pItem->GetCount();
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
if (!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i,false) == EQUIP_ERR_OK )
{
remcount += pItem->GetCount();
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
if(remcount >=count)
return;
if (remcount >=count)
return;
}
}
else
{
ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
pItem->SetCount( pItem->GetCount() - count + remcount );
if (IsInWorld() & update)
pItem->SendUpdateToPlayer( this );
pItem->SetState(ITEM_CHANGED, this);
return;
}
}
else
{
pProto = pItem->GetProto();
ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
pItem->SetCount( pItem->GetCount() - count + remcount );
if( IsInWorld() & update )
pItem->SendUpdateToPlayer( this );
pItem->SetState(ITEM_CHANGED, this);
return;
}
}
}
@ -11042,40 +11050,28 @@ void Player::DestroyZoneLimitedItem( bool update, uint32 new_zone )
// in inventory
for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
{
Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) )
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
}
if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone))
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
{
Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) )
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
}
if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone))
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
// in inventory bags
for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pBag )
{
if (Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
{
Item* pItem = pBag->GetItemByPos(j);
if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) )
DestroyItem( i, j, update);
}
}
}
if (Item* pItem = pBag->GetItemByPos(j))
if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone))
DestroyItem( i, j, update);
// in equipment and bag list
for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)
{
Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) )
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
}
if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone))
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
}
void Player::DestroyConjuredItems( bool update )
@ -11086,40 +11082,23 @@ void Player::DestroyConjuredItems( bool update )
// in inventory
for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
{
Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->GetProto() &&
(pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) &&
(pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
}
if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
if (pItem->IsConjuredConsumable())
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
// in inventory bags
for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pBag )
{
if (Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
{
Item* pItem = pBag->GetItemByPos(j);
if( pItem && pItem->GetProto() &&
(pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) &&
(pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )
DestroyItem( i, j, update);
}
}
}
if (Item* pItem = pBag->GetItemByPos(j))
if (pItem->IsConjuredConsumable())
DestroyItem( i, j, update);
// in equipment and bag list
for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)
{
Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->GetProto() &&
(pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) &&
(pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
}
if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
if (pItem->IsConjuredConsumable())
DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
}
void Player::DestroyItemCount( Item* pItem, uint32 &count, bool update )
@ -12250,7 +12229,7 @@ void Player::SendNewItem(Item *item, uint32 count, bool received, bool created,
data << GetItemCount(item->GetEntry()); // count of items in inventory
if (broadcast && GetGroup())
GetGroup()->BroadcastPacket(&data);
GetGroup()->BroadcastPacket(&data, true);
else
GetSession()->SendPacket(&data);
}
@ -12817,7 +12796,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
GiveXP( XP , NULL );
else
{
int32 money = int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY));
uint32 money = uint32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY));
ModifyMoney( money );
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, money);
}
@ -12826,7 +12805,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
if(pQuest->GetRewOrReqMoney())
{
ModifyMoney( pQuest->GetRewOrReqMoney() );
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney());
if(pQuest->GetRewOrReqMoney() > 0)
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney());
}
// honor reward
@ -14785,9 +14766,15 @@ void Player::_LoadActions(QueryResult *result)
uint8 button = fields[0].GetUInt8();
addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8());
if(addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8()))
m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED;
else
{
sLog.outError( " ...at loading, and will deleted in DB also");
m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED;
// Will deleted in DB at next save (it can create data until save but marked as deleted)
m_actionButtons[button].uState = ACTIONBUTTON_DELETED;
}
}
while( result->NextRow() );
@ -18261,7 +18248,8 @@ void Player::ClearComboPoints()
void Player::SetGroup(Group *group, int8 subgroup)
{
if(group == NULL) m_group.unlink();
if(group == NULL)
m_group.unlink();
else
{
// never use SetGroup without a subgroup unless you specify NULL for group
@ -19215,7 +19203,7 @@ void Player::UpdateAreaDependentAuras( uint32 newArea )
for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
{
// use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date
if(spellmgr.GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,this)!=0)
if(spellmgr.GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,this) != SPELL_CAST_OK)
RemoveAura(iter);
else
++iter;
@ -19348,6 +19336,41 @@ PartyResult Player::CanUninviteFromGroup() const
return PARTY_RESULT_OK;
}
void Player::SetBattleGroundRaid(Group* group, int8 subgroup)
{
//we must move references from m_group to m_originalGroup
SetOriginalGroup(GetGroup(), GetSubGroup());
m_group.unlink();
m_group.link(group, this);
m_group.setSubGroup((uint8)subgroup);
}
void Player::RemoveFromBattleGroundRaid()
{
//remove existing reference
m_group.unlink();
if( Group* group = GetOriginalGroup() )
{
m_group.link(group, this);
m_group.setSubGroup(GetOriginalSubGroup());
}
SetOriginalGroup(NULL);
}
void Player::SetOriginalGroup(Group *group, int8 subgroup)
{
if( group == NULL )
m_originalGroup.unlink();
else
{
// never use SetOriginalGroup without a subgroup unless you specify NULL for group
assert(subgroup >= 0);
m_originalGroup.link(group, this);
m_originalGroup.setSubGroup((uint8)subgroup);
}
}
void Player::UpdateUnderwaterState( Map* m, float x, float y, float z )
{
LiquidData liquid_status;
@ -19425,6 +19448,7 @@ bool Player::CanUseBattleGroundObject()
{
return ( //InBattleGround() && // in battleground - not need, check in other cases
//!IsMounted() && - not correct, player is dismounted when he clicks on flag
//i'm not sure if these two are correct, because invisible players should get visible when they click on flag
!HasStealthAura() && // not stealthed
!HasInvisibilityAura() && // not invisible
!HasAura(SPELL_RECENTLY_DROPPED_FLAG, 0) && // can't pickup
@ -19742,8 +19766,20 @@ void Player::_LoadSkills()
else
SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0));
uint32 vskill = SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)));
// set fixed skill ranges
switch(GetSkillRangeType(pSkill,false))
{
case SKILL_RANGE_LANGUAGE: // 300..300
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(300,300));
break;
case SKILL_RANGE_MONO: // 1..1, grey monolite bar
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(1,1));
break;
default:
break;
}
uint32 vskill = SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)));
learnSkillRewardedSpells(id, vskill);
}

View file

@ -1189,7 +1189,6 @@ class MANGOS_DLL_SPEC Player : public Unit
void AddArmorProficiency(uint32 newflag) { m_ArmorProficiency |= newflag; }
uint32 GetWeaponProficiency() const { return m_WeaponProficiency; }
uint32 GetArmorProficiency() const { return m_ArmorProficiency; }
bool IsInFeralForm() const { return m_form == FORM_CAT || m_form == FORM_BEAR || m_form == FORM_DIREBEAR; }
bool IsUseEquipedWeapon( bool mainhand ) const
{
// disarm applied only to mainhand weapon
@ -1548,7 +1547,7 @@ class MANGOS_DLL_SPEC Player : public Unit
m_cinematic = cine;
}
void addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc);
bool addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc);
void removeActionButton(uint8 button);
void SendInitialActionButtons();
@ -2153,6 +2152,13 @@ class MANGOS_DLL_SPEC Player : public Unit
void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); }
Player* GetNextRandomRaidMember(float radius);
PartyResult CanUninviteFromGroup() const;
// BattleGround Group System
void SetBattleGroundRaid(Group *group, int8 subgroup = -1);
void RemoveFromBattleGroundRaid();
Group * GetOriginalGroup() { return m_originalGroup.getTarget(); }
GroupReference& GetOriginalGroupRef() { return m_originalGroup; }
uint8 GetOriginalSubGroup() const { return m_originalGroup.getSubGroup(); }
void SetOriginalGroup(Group *group, int8 subgroup = -1);
GridReference<Player> &GetGridRef() { return m_gridRef; }
MapReference &GetMapRef() { return m_mapRef; }
@ -2393,6 +2399,7 @@ class MANGOS_DLL_SPEC Player : public Unit
// Groups
GroupReference m_group;
GroupReference m_originalGroup;
Group *m_groupInvite;
uint32 m_groupUpdateMask;
uint64 m_auraUpdateMask;

View file

@ -74,6 +74,9 @@ bool LoadScriptingModule(char const* libName)
||!(testScript->GOQuestAccept =(scriptCallGOQuestAccept )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"GOQuestAccept" ))
||!(testScript->ReceiveEmote =(scriptCallReceiveEmote )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"ReceiveEmote" ))
||!(testScript->ItemUse =(scriptCallItemUse )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"ItemUse" ))
||!(testScript->EffectDummyGameObj =(scriptCallEffectDummyGameObj )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyGameObj" ))
||!(testScript->EffectDummyCreature =(scriptCallEffectDummyCreature )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyCreature" ))
||!(testScript->EffectDummyItem =(scriptCallEffectDummyItem )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyItem" ))
||!(testScript->GetAI =(scriptCallGetAI )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"GetAI" ))
||!(testScript->CreateInstanceData =(scriptCallCreateInstanceData )MANGOS_GET_PROC_ADDR(testScript->hScriptsLib,"CreateInstanceData" ))
)

View file

@ -56,6 +56,9 @@ typedef bool(MANGOS_IMPORT * scriptCallGOQuestAccept)(Player *player, GameObject
typedef bool(MANGOS_IMPORT * scriptCallGOChooseReward)(Player *player, GameObject *, Quest const*, uint32 opt );
typedef bool(MANGOS_IMPORT * scriptCallReceiveEmote) ( Player *player, Creature *_Creature, uint32 emote );
typedef bool(MANGOS_IMPORT * scriptCallItemUse) (Player *player, Item *_Item, SpellCastTargets const& targets);
typedef bool(MANGOS_IMPORT * scriptCallEffectDummyGameObj) (Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget);
typedef bool(MANGOS_IMPORT * scriptCallEffectDummyCreature) (Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget);
typedef bool(MANGOS_IMPORT * scriptCallEffectDummyItem) (Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget);
typedef CreatureAI* (MANGOS_IMPORT * scriptCallGetAI) ( Creature *_Creature );
typedef InstanceData* (MANGOS_IMPORT * scriptCallCreateInstanceData) (Map *map);
@ -82,6 +85,9 @@ typedef struct
scriptCallGOQuestAccept GOQuestAccept;
scriptCallReceiveEmote ReceiveEmote;
scriptCallItemUse ItemUse;
scriptCallEffectDummyGameObj EffectDummyGameObj;
scriptCallEffectDummyCreature EffectDummyCreature;
scriptCallEffectDummyItem EffectDummyItem;
scriptCallGetAI GetAI;
scriptCallCreateInstanceData CreateInstanceData;

View file

@ -684,6 +684,194 @@ enum SpellEffects
TOTAL_SPELL_EFFECTS = 163
};
enum SpellCastResult
{
SPELL_FAILED_AFFECTING_COMBAT = 0,
SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 1,
SPELL_FAILED_ALREADY_AT_FULL_MANA = 2,
SPELL_FAILED_ALREADY_AT_FULL_POWER = 3,
SPELL_FAILED_ALREADY_BEING_TAMED = 4,
SPELL_FAILED_ALREADY_HAVE_CHARM = 5,
SPELL_FAILED_ALREADY_HAVE_SUMMON = 6,
SPELL_FAILED_ALREADY_OPEN = 7,
SPELL_FAILED_AURA_BOUNCED = 8,
SPELL_FAILED_AUTOTRACK_INTERRUPTED = 9,
SPELL_FAILED_BAD_IMPLICIT_TARGETS = 10,
SPELL_FAILED_BAD_TARGETS = 11,
SPELL_FAILED_CANT_BE_CHARMED = 12,
SPELL_FAILED_CANT_BE_DISENCHANTED = 13,
SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 14,
SPELL_FAILED_CANT_BE_MILLED = 15,
SPELL_FAILED_CANT_BE_PROSPECTED = 16,
SPELL_FAILED_CANT_CAST_ON_TAPPED = 17,
SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 18,
SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 19,
SPELL_FAILED_CANT_STEALTH = 20,
SPELL_FAILED_CASTER_AURASTATE = 21,
SPELL_FAILED_CASTER_DEAD = 22,
SPELL_FAILED_CHARMED = 23,
SPELL_FAILED_CHEST_IN_USE = 24,
SPELL_FAILED_CONFUSED = 25,
SPELL_FAILED_DONT_REPORT = 26,
SPELL_FAILED_EQUIPPED_ITEM = 27,
SPELL_FAILED_EQUIPPED_ITEM_CLASS = 28,
SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 29,
SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 30,
SPELL_FAILED_ERROR = 31,
SPELL_FAILED_FIZZLE = 32,
SPELL_FAILED_FLEEING = 33,
SPELL_FAILED_FOOD_LOWLEVEL = 34,
SPELL_FAILED_HIGHLEVEL = 35,
SPELL_FAILED_HUNGER_SATIATED = 36,
SPELL_FAILED_IMMUNE = 37,
SPELL_FAILED_INCORRECT_AREA = 38,
SPELL_FAILED_INTERRUPTED = 39,
SPELL_FAILED_INTERRUPTED_COMBAT = 40,
SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 41,
SPELL_FAILED_ITEM_GONE = 42,
SPELL_FAILED_ITEM_NOT_FOUND = 43,
SPELL_FAILED_ITEM_NOT_READY = 44,
SPELL_FAILED_LEVEL_REQUIREMENT = 45,
SPELL_FAILED_LINE_OF_SIGHT = 46,
SPELL_FAILED_LOWLEVEL = 47,
SPELL_FAILED_LOW_CASTLEVEL = 48,
SPELL_FAILED_MAINHAND_EMPTY = 49,
SPELL_FAILED_MOVING = 50,
SPELL_FAILED_NEED_AMMO = 51,
SPELL_FAILED_NEED_AMMO_POUCH = 52,
SPELL_FAILED_NEED_EXOTIC_AMMO = 53,
SPELL_FAILED_NEED_MORE_ITEMS = 54,
SPELL_FAILED_NOPATH = 55,
SPELL_FAILED_NOT_BEHIND = 56,
SPELL_FAILED_NOT_FISHABLE = 57,
SPELL_FAILED_NOT_FLYING = 58,
SPELL_FAILED_NOT_HERE = 59,
SPELL_FAILED_NOT_INFRONT = 60,
SPELL_FAILED_NOT_IN_CONTROL = 61,
SPELL_FAILED_NOT_KNOWN = 62,
SPELL_FAILED_NOT_MOUNTED = 63,
SPELL_FAILED_NOT_ON_TAXI = 64,
SPELL_FAILED_NOT_ON_TRANSPORT = 65,
SPELL_FAILED_NOT_READY = 66,
SPELL_FAILED_NOT_SHAPESHIFT = 67,
SPELL_FAILED_NOT_STANDING = 68,
SPELL_FAILED_NOT_TRADEABLE = 69,
SPELL_FAILED_NOT_TRADING = 70,
SPELL_FAILED_NOT_UNSHEATHED = 71,
SPELL_FAILED_NOT_WHILE_GHOST = 72,
SPELL_FAILED_NOT_WHILE_LOOTING = 73,
SPELL_FAILED_NO_AMMO = 74,
SPELL_FAILED_NO_CHARGES_REMAIN = 75,
SPELL_FAILED_NO_CHAMPION = 76,
SPELL_FAILED_NO_COMBO_POINTS = 77,
SPELL_FAILED_NO_DUELING = 78,
SPELL_FAILED_NO_ENDURANCE = 79,
SPELL_FAILED_NO_FISH = 80,
SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 81,
SPELL_FAILED_NO_MOUNTS_ALLOWED = 82,
SPELL_FAILED_NO_PET = 83,
SPELL_FAILED_NO_POWER = 84,
SPELL_FAILED_NOTHING_TO_DISPEL = 85,
SPELL_FAILED_NOTHING_TO_STEAL = 86,
SPELL_FAILED_ONLY_ABOVEWATER = 87,
SPELL_FAILED_ONLY_DAYTIME = 88,
SPELL_FAILED_ONLY_INDOORS = 89,
SPELL_FAILED_ONLY_MOUNTED = 90,
SPELL_FAILED_ONLY_NIGHTTIME = 91,
SPELL_FAILED_ONLY_OUTDOORS = 92,
SPELL_FAILED_ONLY_SHAPESHIFT = 93,
SPELL_FAILED_ONLY_STEALTHED = 94,
SPELL_FAILED_ONLY_UNDERWATER = 95,
SPELL_FAILED_OUT_OF_RANGE = 96,
SPELL_FAILED_PACIFIED = 97,
SPELL_FAILED_POSSESSED = 98,
SPELL_FAILED_REAGENTS = 99,
SPELL_FAILED_REQUIRES_AREA = 100,
SPELL_FAILED_REQUIRES_SPELL_FOCUS = 101,
SPELL_FAILED_ROOTED = 102,
SPELL_FAILED_SILENCED = 103,
SPELL_FAILED_SPELL_IN_PROGRESS = 104,
SPELL_FAILED_SPELL_LEARNED = 105,
SPELL_FAILED_SPELL_UNAVAILABLE = 106,
SPELL_FAILED_STUNNED = 107,
SPELL_FAILED_TARGETS_DEAD = 108,
SPELL_FAILED_TARGET_AFFECTING_COMBAT = 109,
SPELL_FAILED_TARGET_AURASTATE = 110,
SPELL_FAILED_TARGET_DUELING = 111,
SPELL_FAILED_TARGET_ENEMY = 112,
SPELL_FAILED_TARGET_ENRAGED = 113,
SPELL_FAILED_TARGET_FRIENDLY = 114,
SPELL_FAILED_TARGET_IN_COMBAT = 115,
SPELL_FAILED_TARGET_IS_PLAYER = 116,
SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 117,
SPELL_FAILED_TARGET_NOT_DEAD = 118,
SPELL_FAILED_TARGET_NOT_IN_PARTY = 119,
SPELL_FAILED_TARGET_NOT_LOOTED = 120,
SPELL_FAILED_TARGET_NOT_PLAYER = 121,
SPELL_FAILED_TARGET_NO_POCKETS = 122,
SPELL_FAILED_TARGET_NO_WEAPONS = 123,
SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 124,
SPELL_FAILED_TARGET_UNSKINNABLE = 125,
SPELL_FAILED_THIRST_SATIATED = 126,
SPELL_FAILED_TOO_CLOSE = 127,
SPELL_FAILED_TOO_MANY_OF_ITEM = 128,
SPELL_FAILED_TOTEM_CATEGORY = 129,
SPELL_FAILED_TOTEMS = 130,
SPELL_FAILED_TRY_AGAIN = 131,
SPELL_FAILED_UNIT_NOT_BEHIND = 132,
SPELL_FAILED_UNIT_NOT_INFRONT = 133,
SPELL_FAILED_WRONG_PET_FOOD = 134,
SPELL_FAILED_NOT_WHILE_FATIGUED = 135,
SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 136,
SPELL_FAILED_NOT_WHILE_TRADING = 137,
SPELL_FAILED_TARGET_NOT_IN_RAID = 138,
SPELL_FAILED_TARGET_FREEFORALL = 139,
SPELL_FAILED_NO_EDIBLE_CORPSES = 140,
SPELL_FAILED_ONLY_BATTLEGROUNDS = 141,
SPELL_FAILED_TARGET_NOT_GHOST = 142,
SPELL_FAILED_TRANSFORM_UNUSABLE = 143,
SPELL_FAILED_WRONG_WEATHER = 144,
SPELL_FAILED_DAMAGE_IMMUNE = 145,
SPELL_FAILED_PREVENTED_BY_MECHANIC = 146,
SPELL_FAILED_PLAY_TIME = 147,
SPELL_FAILED_REPUTATION = 148,
SPELL_FAILED_MIN_SKILL = 149,
SPELL_FAILED_NOT_IN_ARENA = 150,
SPELL_FAILED_NOT_ON_SHAPESHIFT = 151,
SPELL_FAILED_NOT_ON_STEALTHED = 152,
SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 153,
SPELL_FAILED_NOT_ON_MOUNTED = 154,
SPELL_FAILED_TOO_SHALLOW = 155,
SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 156,
SPELL_FAILED_TARGET_IS_TRIVIAL = 157,
SPELL_FAILED_BM_OR_INVISGOD = 158,
SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 159,
SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 160,
SPELL_FAILED_NOT_IDLE = 161,
SPELL_FAILED_NOT_INACTIVE = 162,
SPELL_FAILED_PARTIAL_PLAYTIME = 163,
SPELL_FAILED_NO_PLAYTIME = 164,
SPELL_FAILED_NOT_IN_BATTLEGROUND = 165,
SPELL_FAILED_NOT_IN_RAID_INSTANCE = 166,
SPELL_FAILED_ONLY_IN_ARENA = 167,
SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 168,
SPELL_FAILED_ON_USE_ENCHANT = 169,
SPELL_FAILED_NOT_ON_GROUND = 170,
SPELL_FAILED_CUSTOM_ERROR = 171,
SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 172,
SPELL_FAILED_TOO_MANY_SOCKETS = 173,
SPELL_FAILED_INVALID_GLYPH = 174,
SPELL_FAILED_UNIQUE_GLYPH = 175,
SPELL_FAILED_GLYPH_SOCKET_LOCKED = 176,
SPELL_FAILED_NO_VALID_TARGETS = 177,
SPELL_FAILED_ITEM_AT_MAX_CHARGES = 178,
SPELL_FAILED_NOT_IN_BARBERSHOP = 179,
SPELL_FAILED_FISHING_TOO_LOW = 180,
SPELL_FAILED_UNKNOWN = 181,
SPELL_CAST_OK = 255 //custom value, don't must be send to client
};
// Spell aura states
enum AuraState
{ // (C) used in caster aura state (T) used in target aura state
@ -841,10 +1029,11 @@ enum Targets
TARGET_SINGLE_FRIEND_2 = 57,
TARGET_AREAEFFECT_PARTY_AND_CLASS = 61,
TARGET_DUELVSPLAYER_COORDINATES = 63,
TARGET_BEHIND_VICTIM = 65, // uses in teleport behind spells
TARGET_BEHIND_VICTIM = 65, // uses in teleport behind spells, caster/target dependent from spell effect
TARGET_DYNAMIC_OBJECT_COORDINATES = 76,
TARGET_SINGLE_ENEMY = 77,
TARGET_SELF2 = 87,
TARGET_DIRECTLY_FORWARD = 89,
TARGET_NONCOMBAT_PET = 90,
};
@ -1698,6 +1887,8 @@ inline uint8 ClassByQuestSort(int32 QuestSort)
enum SkillType
{
SKILL_NONE = 0,
SKILL_FROST = 6,
SKILL_FIRE = 8,
SKILL_ARMS = 26,
@ -1852,6 +2043,20 @@ enum SkillType
#define MAX_SKILL_TYPE 789
inline SkillType SkillByLockType(LockType locktype)
{
switch(locktype)
{
case LOCKTYPE_PICKLOCK: return SKILL_LOCKPICKING;
case LOCKTYPE_HERBALISM: return SKILL_HERBALISM;
case LOCKTYPE_MINING: return SKILL_MINING;
case LOCKTYPE_FISHING: return SKILL_FISHING;
case LOCKTYPE_INSCRIPTION: return SKILL_INSCRIPTION;
default: break;
}
return SKILL_NONE;
}
inline uint32 SkillByQuestSort(int32 QuestSort)
{
switch(QuestSort)

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@
#define __SPELL_H
#include "GridDefines.h"
#include "SharedDefines.h"
class WorldSession;
class Unit;
@ -249,6 +250,7 @@ class Spell
void EffectSummonWild(uint32 i);
void EffectSummonGuardian(uint32 i);
void EffectHealMechanical(uint32 i);
void EffectJump(uint32 i);
void EffectTeleUnitsFaceCaster(uint32 i);
void EffectLearnSkill(uint32 i);
void EffectAddHonor(uint32 i);
@ -331,14 +333,13 @@ class Spell
void cast(bool skipCheck = false);
void finish(bool ok = true);
void TakePower();
uint8 CheckRuneCost(uint32 runeCostID);
void TakeRunePower();
void TakeReagents();
void TakeCastItem();
void TriggerSpell();
uint8 CanCast(bool strict);
int16 PetCanCast(Unit* target);
bool CanAutoCast(Unit* target);
SpellCastResult CheckCast(bool strict);
SpellCastResult CheckPetCast(Unit* target);
// handlers
void handle_immediate();
@ -347,10 +348,11 @@ class Spell
void _handle_immediate_phase();
void _handle_finish_phase();
uint8 CheckItems();
uint8 CheckRange(bool strict);
uint8 CheckPower();
uint8 CheckCasterAuras() const;
SpellCastResult CheckItems();
SpellCastResult CheckRange(bool strict);
SpellCastResult CheckPower();
SpellCastResult CheckRuneCost(uint32 runeCostID);
SpellCastResult CheckCasterAuras() const;
int32 CalculateDamage(uint8 i, Unit* target) { return m_caster->CalculateSpellDamage(m_spellInfo,i,m_currentBasePoints[i],target); }
int32 CalculatePowerCost();
@ -370,8 +372,9 @@ class Spell
Unit* SelectMagnetTarget();
bool CheckTarget( Unit* target, uint32 eff );
bool CanAutoCast(Unit* target);
void SendCastResult(uint8 result);
void SendCastResult(SpellCastResult result);
void SendSpellStart();
void SendSpellGo();
void SendSpellCooldown();
@ -546,6 +549,7 @@ class Spell
void DoAllEffectOnTarget(GOTargetInfo *target);
void DoAllEffectOnTarget(ItemTargetInfo *target);
bool IsAliveUnitPresentInTargetList();
SpellCastResult CanOpenLock(uint32 effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);
// -------------------------------------------
//List For Triggered Spells

View file

@ -39,6 +39,7 @@
#include "Formulas.h"
#include "BattleGround.h"
#include "CreatureAI.h"
#include "ScriptCalls.h"
#include "Util.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
@ -1442,7 +1443,7 @@ void Aura::TriggerSpell()
caster->ModifyPower( POWER_MANA, mana );
caster->SendEnergizeSpellLog(caster, 23493, mana, POWER_MANA);
}
break;
return;
}
// // Stoneclaw Totem Passive TEST
// case 23792: break;
@ -1510,8 +1511,11 @@ void Aura::TriggerSpell()
// case 28522: break;
// // Silithyst
// case 29519: break;
// // Inoculate Nestlewood Owlkin
case 29528: trigger_spell_id = 28713; break;
// Inoculate Nestlewood Owlkin
case 29528:
if(target->GetTypeId()!=TYPEID_UNIT)// prevent error reports in case ignored player target
return;
break;
// // Overload
// case 29768: break;
// // Return Fire
@ -1553,7 +1557,6 @@ void Aura::TriggerSpell()
creature->SetHealth(0); // just for nice GM-mode view
}
return;
break;
}
// Quake
case 30576: trigger_spell_id = 30571; break;
@ -1934,13 +1937,9 @@ void Aura::TriggerSpell()
default:
break;
}
// Reget trigger spell proto
triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id);
if(triggeredSpellInfo == NULL)
{
sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex());
return;
}
}
else
{
@ -1992,8 +1991,12 @@ void Aura::TriggerSpell()
}
}
}
// All ok cast by default case
caster->CastSpell(target, triggeredSpellInfo, true, 0, this);
if(triggeredSpellInfo)
caster->CastSpell(target, triggeredSpellInfo, true, 0, this);
else if(target->GetTypeId()!=TYPEID_UNIT || !Script->EffectDummyCreature(caster, GetId(), GetEffIndex(), (Creature*)target))
sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex());
}
void Aura::TriggerSpellWithValue()
@ -2261,6 +2264,45 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
}
case SPELLFAMILY_DRUID:
{
switch(GetId())
{
case 34246: // Idol of the Emerald Queen
{
if (m_target->GetTypeId() != TYPEID_PLAYER)
return;
if(apply)
{
SpellModifier *mod = new SpellModifier;
mod->op = SPELLMOD_DOT;
mod->value = m_modifier.m_amount/7;
mod->type = SPELLMOD_FLAT;
mod->spellId = GetId();
mod->mask = 0x001000000000LL;
mod->mask2= 0LL;
m_spellmod = mod;
}
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
return;
}
case 61336: // Survival Instincts
{
if(apply)
{
if (!m_target->IsInFeralForm())
return;
int32 bp0 = int32(m_target->GetMaxHealth() * m_modifier.m_amount / 100);
m_target->CastCustomSpell(m_target, 50322, &bp0, NULL, NULL, true);
}
else
m_target-> RemoveAurasDueToSpell(50322);
return;
}
}
// Lifebloom
if ( GetSpellProto()->SpellFamilyFlags & 0x1000000000LL )
{
@ -2300,25 +2342,6 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
((Player*)m_target)->UpdateAttackPowerAndDamage();
return;
}
// Idol of the Emerald Queen
if ( GetId() == 34246 && m_target->GetTypeId()==TYPEID_PLAYER )
{
if(apply)
{
SpellModifier *mod = new SpellModifier;
mod->op = SPELLMOD_DOT;
mod->value = m_modifier.m_amount/7;
mod->type = SPELLMOD_FLAT;
mod->spellId = GetId();
mod->mask = 0x001000000000LL;
mod->mask2= 0LL;
m_spellmod = mod;
}
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
return;
}
break;
}
case SPELLFAMILY_HUNTER:
@ -3329,7 +3352,7 @@ void Aura::HandleAuraModDisarm(bool apply, bool Real)
return;
// main-hand attack speed already set to special value for feral form already and don't must change and reset at remove.
if (((Player *)m_target)->IsInFeralForm())
if (m_target->IsInFeralForm())
return;
if (apply)
@ -4693,6 +4716,7 @@ void Aura::HandleAuraModIncreaseHealth(bool apply, bool Real)
case 28726: // Nightmare Seed ( Nightmare Seed )
case 34511: // Valor (Bulwark of Kings, Bulwark of the Ancient Kings)
case 44055: // Tremendous Fortitude (Battlemaster's Alacrity)
case 50322: // Survival Instincts
{
if(Real)
{
@ -5924,6 +5948,15 @@ void Aura::PeriodicTick()
}
case SPELL_AURA_PERIODIC_MANA_LEECH:
{
if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue >= MAX_POWERS)
return;
Powers power = Powers(m_modifier.m_miscvalue);
// power type might have changed between aura applying and tick (druid's shapeshift)
if(m_target->getPowerType() != power)
return;
Unit *pCaster = GetCaster();
if(!pCaster)
return;
@ -5942,18 +5975,20 @@ void Aura::PeriodicTick()
// ignore non positive values (can be result apply spellmods to aura damage
uint32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
// Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana)
// It's mana percent cost spells, m_modifier.m_amount is percent drain from target
if (m_spellProto->ManaCostPercentage)
{
// max value
uint32 maxmana = pCaster->GetMaxPower(power) * pdamage * 2 / 100;
pdamage = m_target->GetMaxPower(power) * pdamage / 100;
if(pdamage > maxmana)
pdamage = maxmana;
}
sLog.outDetail("PeriodicTick: %u (TypeId: %u) power leech of %u (TypeId: %u) for %u dmg inflicted by %u",
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue >= MAX_POWERS)
break;
Powers power = Powers(m_modifier.m_miscvalue);
// power type might have changed between aura applying and tick (druid's shapeshift)
if(m_target->getPowerType() != power)
break;
int32 drain_amount = m_target->GetPower(power) > pdamage ? pdamage : m_target->GetPower(power);
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)

View file

@ -99,7 +99,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
&Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
&Spell::EffectUnused, // 41 SPELL_EFFECT_JUMP
&Spell::EffectUnused, // 42 SPELL_EFFECT_JUMP2
&Spell::EffectJump, // 42 SPELL_EFFECT_JUMP2
&Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
&Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
&Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
@ -1119,7 +1119,7 @@ void Spell::EffectDummy(uint32 i)
return;
unitTarget->CastSpell(unitTarget, 58419, true);
break;
return;
}
case 58420: // Portal to Stormwind
{
@ -1127,7 +1127,7 @@ void Spell::EffectDummy(uint32 i)
return;
unitTarget->CastSpell(unitTarget, 58421, true);
break;
return;
}
}
@ -1750,6 +1750,15 @@ void Spell::EffectDummy(uint32 i)
m_caster->AddPetAura(petSpell);
return;
}
// Script based implementation. Must be used only for not good for implementation in core spell effects
// So called only for not proccessed cases
if(gameObjTarget)
Script->EffectDummyGameObj(m_caster, m_spellInfo->Id, i, gameObjTarget);
else if(unitTarget && unitTarget->GetTypeId()==TYPEID_UNIT)
Script->EffectDummyCreature(m_caster, m_spellInfo->Id, i, (Creature*)unitTarget);
else if(itemTarget)
Script->EffectDummyItem(m_caster, m_spellInfo->Id, i, itemTarget);
}
void Spell::EffectTriggerSpellWithValue(uint32 i)
@ -2000,6 +2009,55 @@ void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo, true, m_CastItem, 0, m_originalCasterGUID);
}
void Spell::EffectJump(uint32 i)
{
if(m_caster->isInFlight())
return;
// Init dest coordinates
float x,y,z,o;
if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
{
x = m_targets.m_destX;
y = m_targets.m_destY;
z = m_targets.m_destZ;
if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_BEHIND_VICTIM)
{
// explicit cast data from client or server-side cast
// some spell at client send caster
Unit* pTarget = NULL;
if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=m_caster)
pTarget = m_targets.getUnitTarget();
else if(unitTarget->getVictim())
pTarget = m_caster->getVictim();
else if(m_caster->GetTypeId() == TYPEID_PLAYER)
pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation();
}
else
o = m_caster->GetOrientation();
}
else if(unitTarget)
{
unitTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
o = m_caster->GetOrientation();
}
else if(gameObjTarget)
{
gameObjTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
o = m_caster->GetOrientation();
}
else
{
sLog.outError( "Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id );
return;
}
m_caster->NearTeleportTo(x,y,z,o,true);
}
void Spell::EffectTeleportUnits(uint32 i)
{
if(!unitTarget || unitTarget->isInFlight())
@ -2018,45 +2076,38 @@ void Spell::EffectTeleportUnits(uint32 i)
}
case TARGET_TABLE_X_Y_Z_COORDINATES:
{
// TODO: Only players can teleport?
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
if(!st)
{
sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u", m_spellInfo->Id );
return;
}
((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0);
if(st->target_mapId==unitTarget->GetMapId())
unitTarget->NearTeleportTo(st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster);
else if(unitTarget->GetTypeId()==TYPEID_PLAYER)
((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0);
break;
}
case TARGET_BEHIND_VICTIM:
{
// Get selected target for player (or victim for units)
Unit *pTarget = NULL;
if(m_caster->GetTypeId() == TYPEID_PLAYER)
pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
else
pTarget = m_caster->getVictim();
// No target present - return
if (!pTarget)
return;
// explicit cast data from client or server-side cast
// some spell at client send caster
if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=unitTarget)
pTarget = m_targets.getUnitTarget();
else if(unitTarget->getVictim())
pTarget = unitTarget->getVictim();
else if(unitTarget->GetTypeId() == TYPEID_PLAYER)
pTarget = ObjectAccessor::GetUnit(*unitTarget, ((Player*)unitTarget)->GetSelection());
// Init dest coordinates
uint32 mapid = m_caster->GetMapId();
float x = m_targets.m_destX;
float y = m_targets.m_destY;
float z = m_targets.m_destZ;
float orientation = pTarget->GetOrientation();
// Teleport
if(unitTarget->GetTypeId() == TYPEID_PLAYER)
((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
else
{
m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
WorldPacket data;
unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
unitTarget->SendMessageToSet(&data, false);
}
float orientation = pTarget ? pTarget->GetOrientation() : unitTarget->GetOrientation();
unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster);
return;
}
default:
@ -2074,15 +2125,7 @@ void Spell::EffectTeleportUnits(uint32 i)
float z = m_targets.m_destZ;
float orientation = unitTarget->GetOrientation();
// Teleport
if(unitTarget->GetTypeId() == TYPEID_PLAYER)
((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
else
{
m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
WorldPacket data;
unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
unitTarget->SendMessageToSet(&data, false);
}
unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster);
return;
}
}
@ -2903,7 +2946,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
player->SendLoot(guid, loottype);
}
void Spell::EffectOpenLock(uint32 /*i*/)
void Spell::EffectOpenLock(uint32 effIndex)
{
if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
{
@ -2913,7 +2956,6 @@ void Spell::EffectOpenLock(uint32 /*i*/)
Player* player = (Player*)m_caster;
LootType loottype = LOOT_CORPSE;
uint32 lockId = 0;
uint64 guid = 0;
@ -2925,7 +2967,7 @@ void Spell::EffectOpenLock(uint32 /*i*/)
if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
{
//CanUseBattleGroundObject() already called in CanCast()
//CanUseBattleGroundObject() already called in CheckCast()
// in battleground check
if(BattleGround *bg = player->GetBattleGround())
{
@ -2937,7 +2979,7 @@ void Spell::EffectOpenLock(uint32 /*i*/)
}
else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
{
//CanUseBattleGroundObject() already called in CanCast()
//CanUseBattleGroundObject() already called in CheckCast()
// in battleground check
if(BattleGround *bg = player->GetBattleGround())
{
@ -2960,91 +3002,39 @@ void Spell::EffectOpenLock(uint32 /*i*/)
return;
}
if(!lockId) // possible case for GO and maybe for items.
SkillType skillId = SKILL_NONE;
int32 reqSkillValue = 0;
int32 skillValue;
SpellCastResult res = CanOpenLock(effIndex,lockId,skillId,reqSkillValue,skillValue);
if(res != SPELL_CAST_OK)
{
SendLoot(guid, loottype);
SendCastResult(res);
return;
}
// Get LockInfo
LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
SendLoot(guid, LOOT_SKINNING);
if (!lockInfo)
// not allow use skill grow at item base open
if(!m_CastItem && skillId != SKILL_NONE)
{
sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
(gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
SendCastResult(SPELL_FAILED_BAD_TARGETS);
return;
}
// check key
for(int i = 0; i < 8; ++i)
{
// Type==1 This means lockInfo->Index[i] is an item
if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i])
{
SendLoot(guid, loottype);
return;
}
}
uint32 SkillId = 0;
// Check and skill-up skill
if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
SkillId = m_spellInfo->EffectMiscValue[1];
// pickpocketing spells
else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
SkillId = SKILL_LOCKPICKING;
// skill bonus provided by casting spell (mostly item spells)
uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
uint32 reqSkillValue = lockInfo->Skill[0];
if(lockInfo->Skill[1]) // required pick lock skill applying
{
if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
{
SendCastResult(SPELL_FAILED_FIZZLE);
return;
}
reqSkillValue = lockInfo->Skill[1];
}
else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
{
SendCastResult(SPELL_FAILED_BAD_TARGETS);
return;
}
if ( SkillId )
{
loottype = LOOT_SKINNING;
if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
{
SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
return;
}
// update skill if really known
if(uint32 SkillValue = player->GetPureSkillValue(SkillId))
if(uint32 pureSkillValue = player->GetPureSkillValue(skillId))
{
if(gameObjTarget)
{
// Allow one skill-up until respawned
if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue) )
gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
}
else if(itemTarget)
{
// Do one skill-up
player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue);
}
}
}
SendLoot(guid, loottype);
}
void Spell::EffectSummonChangeItem(uint32 i)
@ -3743,16 +3733,12 @@ void Spell::EffectTeleUnitsFaceCaster(uint32 i)
if(unitTarget->isInFlight())
return;
uint32 mapid = m_caster->GetMapId();
float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
float fx,fy,fz;
m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
if(unitTarget->GetTypeId() == TYPEID_PLAYER)
((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
else
m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
unitTarget->NearTeleportTo(fx,fy,fz,-m_caster->GetOrientation(),unitTarget==m_caster);
}
void Spell::EffectLearnSkill(uint32 i)
@ -3773,17 +3759,26 @@ void Spell::EffectAddHonor(uint32 /*i*/)
if(unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 honor_reward = MaNGOS::Honor::hk_honor_at_level(unitTarget->getLevel(), damage);
sLog.outDebug("SpellEffect::AddHonor called for spell_id %u, that rewards %u honor points to player: %u", m_spellInfo->Id, honor_reward, ((Player*)unitTarget)->GetGUIDLow());
// not scale value for item based reward (/10 value expected)
if(m_CastItem)
{
((Player*)unitTarget)->RewardHonor(NULL, 1, damage/10);
sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(),((Player*)unitTarget)->GetGUIDLow());
return;
}
// do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80
if( damage <= 50 )
if( damage <= 50)
{
uint32 honor_reward = MaNGOS::Honor::hk_honor_at_level(unitTarget->getLevel(), damage);
((Player*)unitTarget)->RewardHonor(NULL, 1, honor_reward);
sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, ((Player*)unitTarget)->GetGUIDLow());
}
else
{
//maybe we have correct honor_gain in damage already
((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
sLog.outError("SpellEffect::AddHonor called for spell_id %u, that rewards %d * honor for one honorable kill and it is too much (%u of honor) for player: %u", m_spellInfo->Id, damage, honor_reward, ((Player*)unitTarget)->GetGUIDLow());
sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
}
}
@ -5757,7 +5752,6 @@ void Spell::EffectMomentMove(uint32 i)
if( m_spellInfo->rangeIndex== 1) //self range
{
uint32 mapid = m_caster->GetMapId();
float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
// before caster
@ -5767,7 +5761,7 @@ void Spell::EffectMomentMove(uint32 i)
unitTarget->GetPosition(ox,oy,oz);
float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(unitTarget->GetMapId(), ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
{
fx = fx2;
fy = fy2;
@ -5775,10 +5769,7 @@ void Spell::EffectMomentMove(uint32 i)
unitTarget->UpdateGroundPositionZ(fx,fy,fz);
}
if(unitTarget->GetTypeId() == TYPEID_PLAYER)
((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
else
m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
unitTarget->NearTeleportTo(fx, fy, fz, unitTarget->GetOrientation(),unitTarget==m_caster);
}
}

View file

@ -317,6 +317,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
{
case 13139: // net-o-matic special effect
case 23445: // evil twin
case 35679: // Protectorate Demolitionist
case 38637: // Nether Exhaustion (red)
case 38638: // Nether Exhaustion (green)
case 38639: // Nether Exhaustion (blue)
@ -535,13 +536,13 @@ bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId)
return false;
}
uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
{
// talents that learn spells can have stance requirements that need ignore
// (this requirement only for client-side stance show in talent description)
if( GetTalentSpellCost(spellInfo->Id) > 0 &&
(spellInfo->Effect[0]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[1]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[2]==SPELL_EFFECT_LEARN_SPELL) )
return 0;
return SPELL_CAST_OK;
uint32 stanceMask = (form ? 1 << (form - 1) : 0);
@ -549,7 +550,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
return SPELL_FAILED_NOT_SHAPESHIFT;
if (stanceMask & spellInfo->Stances) // can explicitly be casted in this stance
return 0;
return SPELL_CAST_OK;
bool actAsShifted = false;
if (form > 0)
@ -558,7 +559,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
if (!shapeInfo)
{
sLog.outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form);
return 0;
return SPELL_CAST_OK;
}
actAsShifted = !(shapeInfo->flags1 & 1); // shapeshift acts as normal form for spells
}
@ -577,7 +578,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
return SPELL_FAILED_ONLY_SHAPESHIFT;
}
return 0;
return SPELL_CAST_OK;
}
void SpellMgr::LoadSpellTargetPositions()
@ -1336,6 +1337,10 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
// Cat Energy (Feral T4 (2)) and Omen of Clarity
if( spellInfo_1->Id == 16864 && spellInfo_2->Id == 37311 || spellInfo_2->Id == 16864 && spellInfo_1->Id == 37311 )
return false;
// Survival Instincts and Survival Instincts
if( spellInfo_1->Id == 61336 && spellInfo_2->Id == 50322 || spellInfo_2->Id == 61336 && spellInfo_1->Id == 50322 )
return false;
}
// Leader of the Pack and Scroll of Stamina (multi-family check)
@ -2559,7 +2564,7 @@ void SpellMgr::LoadSpellAreas()
sLog.outString( ">> Loaded %u spell area requirements", count );
}
uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player)
SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player)
{
// normal case
if( spellInfo->AreaGroupId > 0)
@ -2585,7 +2590,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint
for(SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
{
if(itr->second.IsFitToRequirements(player,zone_id,area_id))
return 0;
return SPELL_CAST_OK;
}
return SPELL_FAILED_INCORRECT_AREA;
}
@ -2595,9 +2600,9 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint
{
case 23333: // Warsong Flag
case 23335: // Silverwing Flag
return map_id == 489 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA;
return map_id == 489 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
case 34976: // Netherstorm Flag
return map_id == 566 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA;
return map_id == 566 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
case 2584: // Waiting to Resurrect
case 22011: // Spirit Heal Channel
case 22012: // Spirit Heal
@ -2610,7 +2615,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint
if(!mapEntry)
return SPELL_FAILED_INCORRECT_AREA;
return mapEntry->IsBattleGround() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA;
return mapEntry->IsBattleGround() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
}
case 44521: // Preparation
{
@ -2625,7 +2630,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint
return SPELL_FAILED_REQUIRES_AREA;
BattleGround* bg = player->GetBattleGround();
return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA;
return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
}
case 32724: // Gold Team (Alliance)
case 32725: // Green Team (Alliance)
@ -2636,7 +2641,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint
if(!mapEntry)
return SPELL_FAILED_INCORRECT_AREA;
return mapEntry->IsBattleArena() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA;
return mapEntry->IsBattleArena() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
}
case 32727: // Arena Preparation
{
@ -2651,11 +2656,11 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint
return SPELL_FAILED_REQUIRES_AREA;
BattleGround* bg = player->GetBattleGround();
return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA;
return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
}
}
return 0;
return SPELL_CAST_OK;
}
void SpellMgr::LoadSkillLineAbilityMap()

View file

@ -37,192 +37,6 @@ class Spell;
extern SQLStorage sSpellThreatStore;
enum SpellFailedReason
{
SPELL_FAILED_AFFECTING_COMBAT = 0,
SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 1,
SPELL_FAILED_ALREADY_AT_FULL_MANA = 2,
SPELL_FAILED_ALREADY_AT_FULL_POWER = 3,
SPELL_FAILED_ALREADY_BEING_TAMED = 4,
SPELL_FAILED_ALREADY_HAVE_CHARM = 5,
SPELL_FAILED_ALREADY_HAVE_SUMMON = 6,
SPELL_FAILED_ALREADY_OPEN = 7,
SPELL_FAILED_AURA_BOUNCED = 8,
SPELL_FAILED_AUTOTRACK_INTERRUPTED = 9,
SPELL_FAILED_BAD_IMPLICIT_TARGETS = 10,
SPELL_FAILED_BAD_TARGETS = 11,
SPELL_FAILED_CANT_BE_CHARMED = 12,
SPELL_FAILED_CANT_BE_DISENCHANTED = 13,
SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 14,
SPELL_FAILED_CANT_BE_MILLED = 15,
SPELL_FAILED_CANT_BE_PROSPECTED = 16,
SPELL_FAILED_CANT_CAST_ON_TAPPED = 17,
SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 18,
SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 19,
SPELL_FAILED_CANT_STEALTH = 20,
SPELL_FAILED_CASTER_AURASTATE = 21,
SPELL_FAILED_CASTER_DEAD = 22,
SPELL_FAILED_CHARMED = 23,
SPELL_FAILED_CHEST_IN_USE = 24,
SPELL_FAILED_CONFUSED = 25,
SPELL_FAILED_DONT_REPORT = 26,
SPELL_FAILED_EQUIPPED_ITEM = 27,
SPELL_FAILED_EQUIPPED_ITEM_CLASS = 28,
SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 29,
SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 30,
SPELL_FAILED_ERROR = 31,
SPELL_FAILED_FIZZLE = 32,
SPELL_FAILED_FLEEING = 33,
SPELL_FAILED_FOOD_LOWLEVEL = 34,
SPELL_FAILED_HIGHLEVEL = 35,
SPELL_FAILED_HUNGER_SATIATED = 36,
SPELL_FAILED_IMMUNE = 37,
SPELL_FAILED_INCORRECT_AREA = 38,
SPELL_FAILED_INTERRUPTED = 39,
SPELL_FAILED_INTERRUPTED_COMBAT = 40,
SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 41,
SPELL_FAILED_ITEM_GONE = 42,
SPELL_FAILED_ITEM_NOT_FOUND = 43,
SPELL_FAILED_ITEM_NOT_READY = 44,
SPELL_FAILED_LEVEL_REQUIREMENT = 45,
SPELL_FAILED_LINE_OF_SIGHT = 46,
SPELL_FAILED_LOWLEVEL = 47,
SPELL_FAILED_LOW_CASTLEVEL = 48,
SPELL_FAILED_MAINHAND_EMPTY = 49,
SPELL_FAILED_MOVING = 50,
SPELL_FAILED_NEED_AMMO = 51,
SPELL_FAILED_NEED_AMMO_POUCH = 52,
SPELL_FAILED_NEED_EXOTIC_AMMO = 53,
SPELL_FAILED_NEED_MORE_ITEMS = 54,
SPELL_FAILED_NOPATH = 55,
SPELL_FAILED_NOT_BEHIND = 56,
SPELL_FAILED_NOT_FISHABLE = 57,
SPELL_FAILED_NOT_FLYING = 58,
SPELL_FAILED_NOT_HERE = 59,
SPELL_FAILED_NOT_INFRONT = 60,
SPELL_FAILED_NOT_IN_CONTROL = 61,
SPELL_FAILED_NOT_KNOWN = 62,
SPELL_FAILED_NOT_MOUNTED = 63,
SPELL_FAILED_NOT_ON_TAXI = 64,
SPELL_FAILED_NOT_ON_TRANSPORT = 65,
SPELL_FAILED_NOT_READY = 66,
SPELL_FAILED_NOT_SHAPESHIFT = 67,
SPELL_FAILED_NOT_STANDING = 68,
SPELL_FAILED_NOT_TRADEABLE = 69,
SPELL_FAILED_NOT_TRADING = 70,
SPELL_FAILED_NOT_UNSHEATHED = 71,
SPELL_FAILED_NOT_WHILE_GHOST = 72,
SPELL_FAILED_NOT_WHILE_LOOTING = 73,
SPELL_FAILED_NO_AMMO = 74,
SPELL_FAILED_NO_CHARGES_REMAIN = 75,
SPELL_FAILED_NO_CHAMPION = 76,
SPELL_FAILED_NO_COMBO_POINTS = 77,
SPELL_FAILED_NO_DUELING = 78,
SPELL_FAILED_NO_ENDURANCE = 79,
SPELL_FAILED_NO_FISH = 80,
SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 81,
SPELL_FAILED_NO_MOUNTS_ALLOWED = 82,
SPELL_FAILED_NO_PET = 83,
SPELL_FAILED_NO_POWER = 84,
SPELL_FAILED_NOTHING_TO_DISPEL = 85,
SPELL_FAILED_NOTHING_TO_STEAL = 86,
SPELL_FAILED_ONLY_ABOVEWATER = 87,
SPELL_FAILED_ONLY_DAYTIME = 88,
SPELL_FAILED_ONLY_INDOORS = 89,
SPELL_FAILED_ONLY_MOUNTED = 90,
SPELL_FAILED_ONLY_NIGHTTIME = 91,
SPELL_FAILED_ONLY_OUTDOORS = 92,
SPELL_FAILED_ONLY_SHAPESHIFT = 93,
SPELL_FAILED_ONLY_STEALTHED = 94,
SPELL_FAILED_ONLY_UNDERWATER = 95,
SPELL_FAILED_OUT_OF_RANGE = 96,
SPELL_FAILED_PACIFIED = 97,
SPELL_FAILED_POSSESSED = 98,
SPELL_FAILED_REAGENTS = 99,
SPELL_FAILED_REQUIRES_AREA = 100,
SPELL_FAILED_REQUIRES_SPELL_FOCUS = 101,
SPELL_FAILED_ROOTED = 102,
SPELL_FAILED_SILENCED = 103,
SPELL_FAILED_SPELL_IN_PROGRESS = 104,
SPELL_FAILED_SPELL_LEARNED = 105,
SPELL_FAILED_SPELL_UNAVAILABLE = 106,
SPELL_FAILED_STUNNED = 107,
SPELL_FAILED_TARGETS_DEAD = 108,
SPELL_FAILED_TARGET_AFFECTING_COMBAT = 109,
SPELL_FAILED_TARGET_AURASTATE = 110,
SPELL_FAILED_TARGET_DUELING = 111,
SPELL_FAILED_TARGET_ENEMY = 112,
SPELL_FAILED_TARGET_ENRAGED = 113,
SPELL_FAILED_TARGET_FRIENDLY = 114,
SPELL_FAILED_TARGET_IN_COMBAT = 115,
SPELL_FAILED_TARGET_IS_PLAYER = 116,
SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 117,
SPELL_FAILED_TARGET_NOT_DEAD = 118,
SPELL_FAILED_TARGET_NOT_IN_PARTY = 119,
SPELL_FAILED_TARGET_NOT_LOOTED = 120,
SPELL_FAILED_TARGET_NOT_PLAYER = 121,
SPELL_FAILED_TARGET_NO_POCKETS = 122,
SPELL_FAILED_TARGET_NO_WEAPONS = 123,
SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 124,
SPELL_FAILED_TARGET_UNSKINNABLE = 125,
SPELL_FAILED_THIRST_SATIATED = 126,
SPELL_FAILED_TOO_CLOSE = 127,
SPELL_FAILED_TOO_MANY_OF_ITEM = 128,
SPELL_FAILED_TOTEM_CATEGORY = 129,
SPELL_FAILED_TOTEMS = 130,
SPELL_FAILED_TRY_AGAIN = 131,
SPELL_FAILED_UNIT_NOT_BEHIND = 132,
SPELL_FAILED_UNIT_NOT_INFRONT = 133,
SPELL_FAILED_WRONG_PET_FOOD = 134,
SPELL_FAILED_NOT_WHILE_FATIGUED = 135,
SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 136,
SPELL_FAILED_NOT_WHILE_TRADING = 137,
SPELL_FAILED_TARGET_NOT_IN_RAID = 138,
SPELL_FAILED_TARGET_FREEFORALL = 139,
SPELL_FAILED_NO_EDIBLE_CORPSES = 140,
SPELL_FAILED_ONLY_BATTLEGROUNDS = 141,
SPELL_FAILED_TARGET_NOT_GHOST = 142,
SPELL_FAILED_TRANSFORM_UNUSABLE = 143,
SPELL_FAILED_WRONG_WEATHER = 144,
SPELL_FAILED_DAMAGE_IMMUNE = 145,
SPELL_FAILED_PREVENTED_BY_MECHANIC = 146,
SPELL_FAILED_PLAY_TIME = 147,
SPELL_FAILED_REPUTATION = 148,
SPELL_FAILED_MIN_SKILL = 149,
SPELL_FAILED_NOT_IN_ARENA = 150,
SPELL_FAILED_NOT_ON_SHAPESHIFT = 151,
SPELL_FAILED_NOT_ON_STEALTHED = 152,
SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 153,
SPELL_FAILED_NOT_ON_MOUNTED = 154,
SPELL_FAILED_TOO_SHALLOW = 155,
SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 156,
SPELL_FAILED_TARGET_IS_TRIVIAL = 157,
SPELL_FAILED_BM_OR_INVISGOD = 158,
SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 159,
SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 160,
SPELL_FAILED_NOT_IDLE = 161,
SPELL_FAILED_NOT_INACTIVE = 162,
SPELL_FAILED_PARTIAL_PLAYTIME = 163,
SPELL_FAILED_NO_PLAYTIME = 164,
SPELL_FAILED_NOT_IN_BATTLEGROUND = 165,
SPELL_FAILED_NOT_IN_RAID_INSTANCE = 166,
SPELL_FAILED_ONLY_IN_ARENA = 167,
SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 168,
SPELL_FAILED_ON_USE_ENCHANT = 169,
SPELL_FAILED_NOT_ON_GROUND = 170,
SPELL_FAILED_CUSTOM_ERROR = 171,
SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 172,
SPELL_FAILED_TOO_MANY_SOCKETS = 173,
SPELL_FAILED_INVALID_GLYPH = 174,
SPELL_FAILED_UNIQUE_GLYPH = 175,
SPELL_FAILED_GLYPH_SOCKET_LOCKED = 176,
SPELL_FAILED_NO_VALID_TARGETS = 177,
SPELL_FAILED_ITEM_AT_MAX_CHARGES = 178,
SPELL_FAILED_NOT_IN_BARBERSHOP = 179,
SPELL_FAILED_FISHING_TOO_LOW = 180,
SPELL_FAILED_UNKNOWN = 181
};
// only used in code
enum SpellCategories
{
@ -428,7 +242,7 @@ inline bool IsAutoRepeatRangedSpell(SpellEntry const* spellInfo)
return (spellInfo->Attributes & SPELL_ATTR_RANGED) && (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG);
}
uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form);
SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form);
inline bool IsChanneledSpell(SpellEntry const* spellInfo)
{
@ -996,7 +810,7 @@ class SpellMgr
return NULL;
}
uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL);
SpellCastResult GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL);
SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const
{

View file

@ -92,8 +92,6 @@ template<class T>
void
TargetedMovementGenerator<T>::Initialize(T &owner)
{
if(!&owner)
return;
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())

View file

@ -2830,7 +2830,7 @@ uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target)
if(attType != BASE_ATTACK && !item )
return 0;
if(((Player*)this)->IsInFeralForm())
if(IsInFeralForm())
return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
// weapon skill or (unarmed for base attack)
@ -2956,7 +2956,7 @@ void Unit::_UpdateAutoRepeatSpell()
if (isAttackReady(RANGED_ATTACK))
{
// Check if able to cast
if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true))
if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK)
{
InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
return;
@ -7120,6 +7120,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE))
RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE);
// in fighting already
if (m_attacking)
{
if (m_attacking == victim)
@ -7133,7 +7134,16 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
}
return false;
}
AttackStop();
// remove old target data
AttackStop(true);
}
// new battle
else
{
// set position before any AI calls/assistance
if(GetTypeId()==TYPEID_UNIT)
((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
}
//Set our target
@ -7142,10 +7152,6 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
if(meleeAttack)
addUnitState(UNIT_STAT_MELEE_ATTACKING);
// set position before any AI calls/assistance
if(GetTypeId()==TYPEID_UNIT)
((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
m_attacking = victim;
m_attacking->_addAttacker(this);
@ -7172,7 +7178,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
return true;
}
bool Unit::AttackStop()
bool Unit::AttackStop(bool targetSwitch /*=false*/)
{
if (!m_attacking)
return false;
@ -7189,11 +7195,9 @@ bool Unit::AttackStop()
InterruptSpell(CURRENT_MELEE_SPELL);
if( GetTypeId()==TYPEID_UNIT )
{
// reset call assistance
// reset only at real combat stop
if(!targetSwitch && GetTypeId()==TYPEID_UNIT )
((Creature*)this)->SetNoCallAssistance(false);
}
SendAttackStop(victim);
@ -9629,7 +9633,7 @@ uint32 Unit::GetCreatureType() const
{
if(GetTypeId() == TYPEID_PLAYER)
{
SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(((Player*)this)->m_form);
SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(m_form);
if(ssEntry && ssEntry->creatureType > 0)
return ssEntry->creatureType;
else
@ -10599,8 +10603,11 @@ Player* Unit::GetSpellModOwner()
}
///----------Pet responses methods-----------------
void Unit::SendPetCastFail(uint32 spellid, uint8 msg)
void Unit::SendPetCastFail(uint32 spellid, SpellCastResult msg)
{
if(msg == SPELL_CAST_OK)
return;
Unit *owner = GetCharmerOrOwner();
if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
return;
@ -11361,3 +11368,19 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
if(Pet* pet = GetPet())
pet->SetPhaseMask(newPhaseMask,true);
}
void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool casting /*= false*/ )
{
if(GetTypeId() == TYPEID_PLAYER)
((Player*)this)->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0));
else
{
GetMap()->CreatureRelocation((Creature*)this, x, y, z, orientation);
WorldPacket data;
// Work strange for many spells: triggered active mover set for targeted player to creature
//BuildTeleportAckMsg(&data, x, y, z, orientation);
BuildHeartBeatMsg(&data);
SendMessageToSet(&data, false);
}
}

View file

@ -75,7 +75,7 @@ enum SpellAuraInterruptFlags
AURA_INTERRUPT_FLAG_MOUNTING = 0x00020000, // 17 removed by mounting
AURA_INTERRUPT_FLAG_NOT_SEATED = 0x00040000, // 18 removed by standing up
AURA_INTERRUPT_FLAG_CHANGE_MAP = 0x00080000, // 19 leaving map/getting teleported
AURA_INTERRUPT_FLAG_UNK20 = 0x00100000, // 20
AURA_INTERRUPT_FLAG_IMMUNE_OR_STEALTH = 0x00100000, // 20 removed when player on himself casts immunity spell or vanish?
AURA_INTERRUPT_FLAG_UNK21 = 0x00200000, // 21
AURA_INTERRUPT_FLAG_UNK22 = 0x00400000, // 22
AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT = 0x00800000, // 23 removed by entering pvp combat
@ -850,7 +850,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
}
bool Attack(Unit *victim, bool meleeAttack);
void CastStop(uint32 except_spellid = 0);
bool AttackStop();
bool AttackStop(bool targetSwitch = false);
void RemoveAllAttackers();
AttackerSet const& getAttackers() const { return m_attackers; }
bool isAttackingPlayer() const;
@ -1066,6 +1066,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false);
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo);
void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false);
void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL);
void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags);
void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL);
@ -1195,8 +1197,11 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint64 m_ObjectSlot[4];
uint32 m_detectInvisibilityMask;
uint32 m_invisibilityMask;
uint32 m_ShapeShiftFormSpellId;
ShapeshiftForm m_form;
bool IsInFeralForm() const { return m_form == FORM_CAT || m_form == FORM_BEAR || m_form == FORM_DIREBEAR; }
float m_modMeleeHitChance;
float m_modRangedHitChance;
float m_modSpellHitChance;
@ -1401,7 +1406,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void ClearComboPointHolders();
///----------Pet responses methods-----------------
void SendPetCastFail(uint32 spellid, uint8 msg);
void SendPetCastFail(uint32 spellid, SpellCastResult msg);
void SendPetActionFeedback (uint8 msg);
void SendPetTalk (uint32 pettalk);
void SendPetSpellCooldown (uint32 spellid, time_t cooltime);

View file

@ -245,11 +245,13 @@ void FlightPathMovementGenerator::Initialize(Player &player)
void FlightPathMovementGenerator::Finalize(Player & player)
{
// remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack)
player.clearUnitState(UNIT_STAT_IN_FLIGHT);
float x, y, z;
i_destinationHolder.GetLocationNow(player.GetMapId(), x, y, z);
player.SetPosition(x, y, z, player.GetOrientation());
player.clearUnitState(UNIT_STAT_IN_FLIGHT);
player.Unmount();
player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);