Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
@@ -2481,6 +2481,12 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList()
|
||||
if (!criteria)
|
||||
continue;
|
||||
|
||||
if (!GetAchievement(criteria->referredAchievement))
|
||||
{
|
||||
LOG_DEBUG("server.loading", "Achievement {} referenced by criteria {} doesn't exist, criteria not loaded.", criteria->referredAchievement, criteria->ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
_achievementCriteriasByType[criteria->requiredType].push_back(criteria);
|
||||
_achievementCriteriaListByAchievement[criteria->referredAchievement].push_back(criteria);
|
||||
|
||||
|
||||
@@ -917,10 +917,13 @@ void BfCapturePoint::SendChangePhase()
|
||||
}
|
||||
}
|
||||
|
||||
bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint)
|
||||
bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint, TeamId team)
|
||||
{
|
||||
ASSERT(capturePoint);
|
||||
|
||||
//At first call using TEAM_NEUTRAL as a checker but never using it, after first call we reset the capturepoints to the new winner of the last WG war
|
||||
if (team == TEAM_NEUTRAL)
|
||||
team = m_team;
|
||||
LOG_DEBUG("bg.battlefield", "Creating capture point {}", capturePoint->GetEntry());
|
||||
|
||||
m_capturePoint = capturePoint->GetGUID();
|
||||
@@ -939,7 +942,7 @@ bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint)
|
||||
m_neutralValuePct = goinfo->capturePoint.neutralPercent;
|
||||
m_minValue = m_maxValue * goinfo->capturePoint.neutralPercent / 100;
|
||||
m_capturePointEntry = capturePoint->GetEntry();
|
||||
if (m_team == TEAM_ALLIANCE)
|
||||
if (team == TEAM_ALLIANCE)
|
||||
{
|
||||
m_value = m_maxValue;
|
||||
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE;
|
||||
|
||||
@@ -104,7 +104,8 @@ public:
|
||||
virtual void ChangeTeam(TeamId /*oldTeam*/) {}
|
||||
virtual void SendChangePhase();
|
||||
|
||||
bool SetCapturePointData(GameObject* capturePoint);
|
||||
//Added team to reset capturepoints on sliders after warTime
|
||||
bool SetCapturePointData(GameObject* capturePoint, TeamId team);
|
||||
GameObject* GetCapturePointGo();
|
||||
GameObject* GetCapturePointGo(WorldObject* obj);
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ bool BattlefieldWG::SetupBattlefield()
|
||||
|
||||
// When between games, the graveyard is controlled by the defending team
|
||||
if (WGGraveYard[i].startcontrol == TEAM_NEUTRAL)
|
||||
graveyard->Initialize(m_DefenderTeam, WGGraveYard[i].gyid);
|
||||
graveyard->Initialize(WGGraveYard[i].gyid == BATTLEFIELD_WG_GY_WORKSHOP_SE || WGGraveYard[i].gyid == BATTLEFIELD_WG_GY_WORKSHOP_SW ? GetAttackerTeam() : m_DefenderTeam, WGGraveYard[i].gyid);
|
||||
else
|
||||
graveyard->Initialize(WGGraveYard[i].startcontrol, WGGraveYard[i].gyid);
|
||||
|
||||
@@ -114,7 +114,7 @@ bool BattlefieldWG::SetupBattlefield()
|
||||
for (uint8 i = 0; i < WG_MAX_WORKSHOP; i++)
|
||||
{
|
||||
WGWorkshop* workshop = new WGWorkshop(this, i);
|
||||
if (i < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST)
|
||||
if (i == BATTLEFIELD_WG_WORKSHOP_SE || i == BATTLEFIELD_WG_WORKSHOP_SW)
|
||||
workshop->GiveControlTo(GetAttackerTeam(), true);
|
||||
else
|
||||
workshop->GiveControlTo(GetDefenderTeam(), true);
|
||||
@@ -262,6 +262,11 @@ void BattlefieldWG::OnBattleStart()
|
||||
if (*itr)
|
||||
(*itr)->UpdateGraveyardAndWorkshop();
|
||||
|
||||
// Set Sliders capture points data to his owners when battle start
|
||||
for (BfCapturePointVector::const_iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
|
||||
(*itr)->SetCapturePointData((*itr)->GetCapturePointGo(),
|
||||
(*itr)->GetCapturePointGo()->GetEntry() == GO_WINTERGRASP_FACTORY_BANNER_SE || (*itr)->GetCapturePointGo()->GetEntry() == GO_WINTERGRASP_FACTORY_BANNER_SW ? GetAttackerTeam() : GetDefenderTeam());
|
||||
|
||||
for (uint8 team = 0; team < 2; ++team)
|
||||
for (GuidUnorderedSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
|
||||
{
|
||||
@@ -375,7 +380,7 @@ void BattlefieldWG::OnBattleEnd(bool endByTimer)
|
||||
// Update all graveyard, control is to defender when no wartime
|
||||
for (uint8 i = 0; i < BATTLEFIELD_WG_GY_HORDE; i++)
|
||||
if (BfGraveyard* graveyard = GetGraveyardById(i))
|
||||
graveyard->GiveControlTo(GetDefenderTeam());
|
||||
graveyard->GiveControlTo(i == BATTLEFIELD_WG_GY_WORKSHOP_SE || i == BATTLEFIELD_WG_GY_WORKSHOP_SW ? GetAttackerTeam() : GetDefenderTeam());
|
||||
|
||||
for (GameObjectSet::const_iterator itr = m_KeepGameObject[GetDefenderTeam()].begin(); itr != m_KeepGameObject[GetDefenderTeam()].end(); ++itr)
|
||||
(*itr)->SetRespawnTime(RESPAWN_IMMEDIATELY);
|
||||
@@ -396,7 +401,10 @@ void BattlefieldWG::OnBattleEnd(bool endByTimer)
|
||||
}
|
||||
|
||||
for (Workshop::const_iterator itr = WorkshopsList.begin(); itr != WorkshopsList.end(); ++itr)
|
||||
{
|
||||
(*itr)->GiveControlTo((*itr)->workshopId == BATTLEFIELD_WG_WORKSHOP_SE || (*itr)->workshopId == BATTLEFIELD_WG_WORKSHOP_SW ? GetAttackerTeam() : GetDefenderTeam(), true);
|
||||
(*itr)->Save();
|
||||
}
|
||||
|
||||
for (uint8 team = 0; team < 2; ++team)
|
||||
{
|
||||
@@ -689,9 +697,9 @@ void BattlefieldWG::OnGameObjectCreate(GameObject* go)
|
||||
{
|
||||
if (workshop->workshopId == workshopId)
|
||||
{
|
||||
WintergraspCapturePoint* capturePoint = new WintergraspCapturePoint(this, GetAttackerTeam());
|
||||
|
||||
capturePoint->SetCapturePointData(go);
|
||||
WintergraspCapturePoint* capturePoint = new WintergraspCapturePoint(this, workshop->teamControl);
|
||||
//Sending neutral team at start to set normal capture points by workshop->teamControl, TEAM_NEUTRAL is ignored at first call
|
||||
capturePoint->SetCapturePointData(go, TEAM_NEUTRAL);
|
||||
capturePoint->LinkToWorkshop(workshop);
|
||||
AddCapturePoint(capturePoint);
|
||||
break;
|
||||
@@ -846,7 +854,7 @@ void BattlefieldWG::OnPlayerJoinWar(Player* player)
|
||||
if (player->GetTeamId() == TEAM_HORDE)
|
||||
player->TeleportTo(571, 5025.857422f, 3674.628906f, 362.737122f, 4.135169f);
|
||||
else
|
||||
player->TeleportTo(571, 5101.284f, 2186.564f, 373.549f, 3.812f);
|
||||
player->TeleportTo(571, 5101.284f, 2186.564f, 365.549f, 3.812f);
|
||||
}
|
||||
|
||||
if (player->GetTeamId() == GetAttackerTeam())
|
||||
|
||||
@@ -1474,6 +1474,17 @@ struct WGWorkshop
|
||||
// Send warning message to all player to inform a faction attack to a workshop
|
||||
// alliance / horde attacking a workshop
|
||||
bf->SendWarning(teamControl ? WorkshopsData[workshopId].attackText : (WorkshopsData[workshopId].attackText + 2));
|
||||
|
||||
// Updating worldstate, update icon to neutral
|
||||
state = BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_INTACT;
|
||||
bf->SendUpdateWorldState(WorkshopsData[workshopId].worldstate, state);
|
||||
|
||||
// Found associate graveyard and update it
|
||||
if (workshopId < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST)
|
||||
if (bf->GetGraveyardById(workshopId))
|
||||
bf->GetGraveyardById(workshopId)->GiveControlTo(team);
|
||||
|
||||
teamControl = team;
|
||||
break;
|
||||
}
|
||||
case TEAM_ALLIANCE:
|
||||
|
||||
@@ -927,7 +927,7 @@ void ArenaTeam::UpdateArenaPointsHelper(std::map<ObjectGuid, uint32>& playerPoin
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaTeam::SaveToDB()
|
||||
void ArenaTeam::SaveToDB(bool forceMemberSave)
|
||||
{
|
||||
if (!sScriptMgr->CanSaveToDB(this))
|
||||
return;
|
||||
@@ -949,6 +949,10 @@ void ArenaTeam::SaveToDB()
|
||||
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
{
|
||||
// Save the effort and go
|
||||
if (itr->WeekGames == 0 && !forceMemberSave)
|
||||
continue;
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ARENA_TEAM_MEMBER);
|
||||
stmt->SetData(0, itr->PersonalRating);
|
||||
stmt->SetData(1, itr->WeekGames);
|
||||
@@ -970,8 +974,12 @@ void ArenaTeam::SaveToDB()
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void ArenaTeam::FinishWeek()
|
||||
bool ArenaTeam::FinishWeek()
|
||||
{
|
||||
// No need to go further than this
|
||||
if (Stats.WeekGames == 0)
|
||||
return false;
|
||||
|
||||
// Reset team stats
|
||||
Stats.WeekGames = 0;
|
||||
Stats.WeekWins = 0;
|
||||
@@ -982,6 +990,8 @@ void ArenaTeam::FinishWeek()
|
||||
itr->WeekGames = 0;
|
||||
itr->WeekWins = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArenaTeam::IsFighting() const
|
||||
|
||||
@@ -182,7 +182,7 @@ public:
|
||||
bool LoadArenaTeamFromDB(QueryResult arenaTeamDataResult);
|
||||
bool LoadMembersFromDB(QueryResult arenaTeamMembersResult);
|
||||
void LoadStatsFromDB(uint32 ArenaTeamId);
|
||||
void SaveToDB();
|
||||
void SaveToDB(bool forceMemberSave = false);
|
||||
|
||||
void BroadcastPacket(WorldPacket* packet);
|
||||
void BroadcastEvent(ArenaTeamEvents event, ObjectGuid guid, uint8 strCount, std::string const& str1, std::string const& str2, std::string const& str3);
|
||||
@@ -206,7 +206,7 @@ public:
|
||||
|
||||
void UpdateArenaPointsHelper(std::map<ObjectGuid, uint32>& PlayerPoints);
|
||||
|
||||
void FinishWeek();
|
||||
bool FinishWeek(); // returns true if arena team played this week
|
||||
void FinishGame(int32 mod, const Map* bgMap);
|
||||
|
||||
void SetPreviousOpponents(uint32 arenaTeamId) { PreviousOpponents = arenaTeamId; }
|
||||
|
||||
@@ -239,8 +239,9 @@ void ArenaTeamMgr::DistributeArenaPoints()
|
||||
{
|
||||
if (ArenaTeam* at = titr->second)
|
||||
{
|
||||
at->FinishWeek();
|
||||
at->SaveToDB();
|
||||
if (at->FinishWeek())
|
||||
at->SaveToDB(true);
|
||||
|
||||
at->NotifyStatsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1863,7 +1863,9 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
|
||||
return false;
|
||||
|
||||
if (!CanDetect(obj, ignoreStealth, !distanceCheck, checkAlert))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1890,7 +1892,9 @@ bool WorldObject::CanDetect(WorldObject const* obj, bool ignoreStealth, bool che
|
||||
if (!ignoreStealth)
|
||||
{
|
||||
if (!seer->CanDetectInvisibilityOf(obj)) // xinef: added ignoreStealth, allow AoE spells to hit invisible targets!
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!seer->CanDetectStealthOf(obj, checkAlert))
|
||||
{
|
||||
@@ -1923,11 +1927,32 @@ bool WorldObject::CanDetectInvisibilityOf(WorldObject const* obj) const
|
||||
// It seems like that only Units are affected by this check (couldn't see arena doors with preparation invisibility)
|
||||
if (obj->ToUnit())
|
||||
{
|
||||
uint32 objMask = m_invisibility.GetFlags() & obj->m_invisibilityDetect.GetFlags();
|
||||
// xinef: include invisible flags of caster in the mask, 2 invisible objects should be able to detect eachother
|
||||
objMask |= m_invisibility.GetFlags() & obj->m_invisibility.GetFlags();
|
||||
if (objMask != m_invisibility.GetFlags())
|
||||
return false;
|
||||
// Permanently invisible creatures should be able to engage non-invisible targets.
|
||||
// ex. Skulking Witch (20882) / Greater Invisibility (16380)
|
||||
bool isPermInvisibleCreature = false;
|
||||
if (Creature const* baseObj = ToCreature())
|
||||
{
|
||||
auto auraEffects = baseObj->GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY);
|
||||
for (auto const effect : auraEffects)
|
||||
{
|
||||
if (SpellInfo const* spell = effect->GetSpellInfo())
|
||||
{
|
||||
if (spell->GetMaxDuration() == -1)
|
||||
{
|
||||
isPermInvisibleCreature = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPermInvisibleCreature)
|
||||
{
|
||||
uint32 objMask = m_invisibility.GetFlags() & obj->m_invisibilityDetect.GetFlags();
|
||||
// xinef: include invisible flags of caster in the mask, 2 invisible objects should be able to detect eachother
|
||||
objMask |= m_invisibility.GetFlags() & obj->m_invisibility.GetFlags();
|
||||
if (objMask != m_invisibility.GetFlags())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < TOTAL_INVISIBILITY_TYPES; ++i)
|
||||
|
||||
@@ -15144,7 +15144,7 @@ void Player::ActivateSpec(uint8 spec)
|
||||
for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
|
||||
{
|
||||
Aura* aura = *iter;
|
||||
if (!HasActiveSpell(aura->GetId()) && !HasTalent(aura->GetId(), GetActiveSpec()))
|
||||
if (!HasActiveSpell(aura->GetId()) && !HasTalent(aura->GetId(), GetActiveSpec()) && !aura->GetCastItemGUID())
|
||||
{
|
||||
aura->Remove();
|
||||
iter = scAuras.begin();
|
||||
|
||||
@@ -13490,7 +13490,7 @@ void Unit::Dismount()
|
||||
if (Player* player = ToPlayer())
|
||||
{
|
||||
sScriptMgr->AnticheatSetUnderACKmount(player);
|
||||
|
||||
ToPlayer()->SetCanTeleport(true);
|
||||
if (Pet* pPet = player->GetPet())
|
||||
{
|
||||
if (pPet->HasUnitFlag(UNIT_FLAG_STUNNED) && !pPet->HasUnitState(UNIT_STATE_STUNNED))
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "ObjectGridLoader.h"
|
||||
#include "CellImpl.h"
|
||||
#include "Corpse.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "DynamicObject.h"
|
||||
@@ -97,13 +98,17 @@ void AddObjectHelper(CellCoord& cell, GameObjectMapType& m, uint32& count, Map*
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgr<T>& m, uint32& count, Map* map)
|
||||
void LoadHelper(CellGuidSet const& /*guid_set*/, CellCoord& /*cell*/, GridRefMgr<T>& /*m*/, uint32& /*count*/, Map* /*map*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <>
|
||||
void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgr<Creature>& m, uint32& count, Map* map)
|
||||
{
|
||||
for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid)
|
||||
{
|
||||
T* obj = new T;
|
||||
Creature* obj = new Creature();
|
||||
ObjectGuid::LowType guid = *i_guid;
|
||||
|
||||
if (!obj->LoadFromDB(guid, map))
|
||||
{
|
||||
delete obj;
|
||||
@@ -111,6 +116,16 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgr<T>& m,
|
||||
}
|
||||
|
||||
AddObjectHelper(cell, m, count, map, obj);
|
||||
|
||||
if (!obj->IsMoveInLineOfSightDisabled() && obj->GetDefaultMovementType() == IDLE_MOTION_TYPE && !obj->isNeedNotify(NOTIFY_VISIBILITY_CHANGED | NOTIFY_AI_RELOCATION))
|
||||
{
|
||||
if (obj->IsAlive() && !obj->HasUnitState(UNIT_STATE_SIGHTLESS) && obj->HasReactState(REACT_AGGRESSIVE) && !obj->IsImmuneToNPC())
|
||||
{
|
||||
// call MoveInLineOfSight for nearby grid creatures
|
||||
Acore::AIRelocationNotifier notifier(*obj);
|
||||
Cell::VisitGridObjects(obj, notifier, 60.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -237,6 +237,13 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
// handle empty bag before CanBeTraded, since that func already has that check
|
||||
if (item->IsNotEmptyBag())
|
||||
{
|
||||
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item->CanBeTraded(true))
|
||||
{
|
||||
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM);
|
||||
@@ -261,12 +268,6 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->IsNotEmptyBag())
|
||||
{
|
||||
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sScriptMgr->CanSendMail(player, receiverGuid, mailbox, subject, body, money, COD, item))
|
||||
{
|
||||
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR);
|
||||
|
||||
@@ -355,8 +355,12 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler()
|
||||
sessionGuard.lock();
|
||||
LogOpcodeText(opcode, sessionGuard);
|
||||
if (_worldSession)
|
||||
{
|
||||
_worldSession->ResetTimeOutTime(true);
|
||||
return ReadDataHandlerResult::Ok;
|
||||
return ReadDataHandlerResult::Ok;
|
||||
}
|
||||
LOG_ERROR("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_KEEP_ALIVE without being authenticated", GetRemoteIpAddress().to_string());
|
||||
return ReadDataHandlerResult::Error;
|
||||
case CMSG_TIME_SYNC_RESP:
|
||||
packetToQueue = new WorldPacket(std::move(packet), GameTime::Now());
|
||||
break;
|
||||
|
||||
@@ -6328,7 +6328,8 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
|
||||
// chance for fail at lockpicking attempt
|
||||
// second check prevent fail at rechecks
|
||||
if (skillId != SKILL_NONE && (!m_selfContainer || ((*m_selfContainer) != this)))
|
||||
// herbalism and mining cannot fail as of patch 3.1.0
|
||||
if (skillId != SKILL_NONE && skillId != SKILL_HERBALISM && skillId != SKILL_MINING && (!m_selfContainer || ((*m_selfContainer) != this)))
|
||||
{
|
||||
// chance for failure in orange lockpick
|
||||
if (skillId == SKILL_LOCKPICKING && reqSkillValue > irand(skillValue - 25, skillValue + 37))
|
||||
|
||||
@@ -4483,6 +4483,18 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx5 |= SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL;
|
||||
});
|
||||
|
||||
// Buffeting Winds of Susurrus
|
||||
ApplySpellFix({ 32474 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(556); // 28 seconds
|
||||
});
|
||||
|
||||
// Quest - Healing Salve
|
||||
ApplySpellFix({ 29314 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->CastTimeEntry = sSpellCastTimesStore.LookupEntry(1); // 0s
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -1193,6 +1193,8 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32
|
||||
return spellId == 56618;
|
||||
else if (team == TEAM_ALLIANCE)
|
||||
return spellId == 56617;
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
// Hellscream's Warsong
|
||||
|
||||
Reference in New Issue
Block a user