Merge branch 'master' into Playerbot
This commit is contained in:
@@ -359,7 +359,7 @@ public:
|
||||
virtual void JustExitedCombat() { }
|
||||
|
||||
/// @brief Called at any Damage to any victim (before damage apply)
|
||||
virtual void DamageDealt(Unit* /*victim*/, uint32& /*damage*/, DamageEffectType /*damageType*/) { }
|
||||
virtual void DamageDealt(Unit* /*victim*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) {}
|
||||
|
||||
/** @brief Called at any Damage from any attacker (before damage apply)
|
||||
*
|
||||
|
||||
@@ -893,7 +893,7 @@ void SmartAI::IsSummonedBy(WorldObject* summoner)
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_JUST_SUMMONED, summoner->ToUnit(), 0, 0, false, nullptr, summoner->ToGameObject());
|
||||
}
|
||||
|
||||
void SmartAI::DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType /*damagetype*/)
|
||||
void SmartAI::DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED_TARGET, doneTo, damage);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ public:
|
||||
void IsSummonedBy(WorldObject* summoner) override;
|
||||
|
||||
// Called at any Damage to any victim (before damage apply)
|
||||
void DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType damagetyp) override;
|
||||
void DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType damagetyp, SpellSchoolMask damageSchoolMask) override;
|
||||
|
||||
// Called when a summoned creature dissapears (UnSommoned)
|
||||
void SummonedCreatureDespawn(Creature* unit) override;
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "SpellMgr.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
|
||||
bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
|
||||
{
|
||||
@@ -580,7 +581,7 @@ void AchievementMgr::SaveToDB(CharacterDatabaseTransaction trans)
|
||||
|
||||
iter->second.changed = false;
|
||||
|
||||
sScriptMgr->OnAchievementSave(trans, GetPlayer(), iter->first, iter->second);
|
||||
sScriptMgr->OnPlayerAchievementSave(trans, GetPlayer(), iter->first, iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +610,7 @@ void AchievementMgr::SaveToDB(CharacterDatabaseTransaction trans)
|
||||
|
||||
iter->second.changed = false;
|
||||
|
||||
sScriptMgr->OnCriteriaSave(trans, GetPlayer(), iter->first, iter->second);
|
||||
sScriptMgr->OnPlayerCriteriaSave(trans, GetPlayer(), iter->first, iter->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -728,7 +729,7 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement)
|
||||
data << GetPlayer()->GetGUID();
|
||||
data << uint32(achievement->ID);
|
||||
data << uint32(0); // display name as plain string in chat (always 0 for guild)
|
||||
sWorld->SendGlobalMessage(&data);
|
||||
sWorldSessionMgr->SendGlobalMessage(&data);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -741,20 +742,15 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement)
|
||||
data << uint32(achievement->ID);
|
||||
std::size_t linkTypePos = data.wpos();
|
||||
data << uint32(1); // display name as clickable link in chat
|
||||
sWorld->SendGlobalMessage(&data, nullptr, teamId);
|
||||
sWorldSessionMgr->SendGlobalMessage(&data, nullptr, teamId);
|
||||
|
||||
data.put<uint32>(linkTypePos, 0); // display name as plain string in chat
|
||||
sWorld->SendGlobalMessage(&data, nullptr, teamId == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE);
|
||||
sWorldSessionMgr->SendGlobalMessage(&data, nullptr, teamId == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE);
|
||||
}
|
||||
}
|
||||
// if player is in world he can tell his friends about new achievement
|
||||
else if (GetPlayer()->IsInWorld())
|
||||
{
|
||||
CellCoord p = Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
|
||||
|
||||
Cell cell(p);
|
||||
cell.SetNoCreate();
|
||||
|
||||
Acore::BroadcastTextBuilder _builder(GetPlayer(), CHAT_MSG_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, GetPlayer()->getGender(), GetPlayer(), achievement->ID);
|
||||
Acore::LocalizedPacketDo<Acore::BroadcastTextBuilder> _localizer(_builder);
|
||||
Acore::PlayerDistWorker<Acore::LocalizedPacketDo<Acore::BroadcastTextBuilder>> _worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _localizer);
|
||||
@@ -2103,7 +2099,7 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry,
|
||||
if (entry->timeLimit && timedIter == _timedAchievements.end())
|
||||
return;
|
||||
|
||||
if (!sScriptMgr->OnBeforeCriteriaProgress(GetPlayer(), entry))
|
||||
if (!sScriptMgr->OnPlayerBeforeCriteriaProgress(GetPlayer(), entry))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -2169,7 +2165,7 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry,
|
||||
|
||||
SendCriteriaUpdate(entry, progress, timeElapsed, true);
|
||||
|
||||
sScriptMgr->OnCriteriaProgress(GetPlayer(), entry);
|
||||
sScriptMgr->OnPlayerCriteriaProgress(GetPlayer(), entry);
|
||||
}
|
||||
|
||||
void AchievementMgr::RemoveCriteriaProgress(const AchievementCriteriaEntry* entry)
|
||||
@@ -2277,7 +2273,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sScriptMgr->OnBeforeAchievementComplete(GetPlayer(), achievement))
|
||||
if (!sScriptMgr->OnPlayerBeforeAchievementComplete(GetPlayer(), achievement))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -2292,7 +2288,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
|
||||
ca.date = GameTime::GetGameTime().count();
|
||||
ca.changed = true;
|
||||
|
||||
sScriptMgr->OnAchievementComplete(GetPlayer(), achievement);
|
||||
sScriptMgr->OnPlayerAchievementComplete(GetPlayer(), achievement);
|
||||
|
||||
// pussywizard: set all progress counters to 0, so progress will be deleted from db during save
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "ObjectMgr.h"
|
||||
#include "Transport.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
// however, for some reasons removing it would cause a damn linking issue
|
||||
@@ -143,7 +144,7 @@ bool Battlefield::Update(uint32 diff)
|
||||
{
|
||||
if (m_Timer <= diff)
|
||||
{
|
||||
if (!IsEnabled() || (!IsWarTime() && sWorld->GetActiveSessionCount() > 3500)) // if WG is disabled or there is more than 3500 connections, switch automaticly
|
||||
if (!IsEnabled() || (!IsWarTime() && sWorldSessionMgr->GetActiveSessionCount() > 3500)) // if WG is disabled or there is more than 3500 connections, switch automaticly
|
||||
{
|
||||
m_isActive = true;
|
||||
EndBattle(false);
|
||||
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
|
||||
virtual ~BfCapturePoint() { }
|
||||
|
||||
virtual void FillInitialWorldStates(WorldPacket& /*data*/) {}
|
||||
virtual void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& /*packet*/) { }
|
||||
|
||||
// Send world state update to all players present
|
||||
void SendUpdateWorldState(uint32 field, uint32 value);
|
||||
@@ -334,7 +334,7 @@ public:
|
||||
|
||||
/// Send all worldstate data to all player in zone.
|
||||
virtual void SendInitWorldStatesToAll() = 0;
|
||||
virtual void FillInitialWorldStates(WorldPacket& /*data*/) = 0;
|
||||
virtual void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& /*packet*/) = 0;
|
||||
|
||||
/// Return if we can use mount in battlefield
|
||||
bool CanFlyIn() { return !m_isActive; }
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "TemporarySummon.h"
|
||||
#include "Vehicle.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
BattlefieldWG::~BattlefieldWG()
|
||||
{
|
||||
@@ -74,7 +75,7 @@ bool BattlefieldWG::SetupBattlefield()
|
||||
|
||||
m_saveTimer = 60000;
|
||||
|
||||
// Init GraveYards
|
||||
// Init Graveyards
|
||||
SetGraveyardNumber(BATTLEFIELD_WG_GRAVEYARD_MAX);
|
||||
|
||||
// Load from db
|
||||
@@ -102,12 +103,12 @@ bool BattlefieldWG::SetupBattlefield()
|
||||
BfGraveyardWG* graveyard = new BfGraveyardWG(this);
|
||||
|
||||
// When between games, the graveyard is controlled by the defending team
|
||||
if (WGGraveYard[i].startcontrol == TEAM_NEUTRAL)
|
||||
graveyard->Initialize(WGGraveYard[i].gyid == BATTLEFIELD_WG_GY_WORKSHOP_SE || WGGraveYard[i].gyid == BATTLEFIELD_WG_GY_WORKSHOP_SW ? GetAttackerTeam() : m_DefenderTeam, WGGraveYard[i].gyid);
|
||||
if (WGGraveyard[i].startcontrol == TEAM_NEUTRAL)
|
||||
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);
|
||||
graveyard->Initialize(WGGraveyard[i].startcontrol, WGGraveyard[i].gyid);
|
||||
|
||||
graveyard->SetTextId(WGGraveYard[i].textid);
|
||||
graveyard->SetTextId(WGGraveyard[i].textid);
|
||||
m_GraveyardList[i] = graveyard;
|
||||
}
|
||||
|
||||
@@ -933,46 +934,46 @@ uint32 BattlefieldWG::GetData(uint32 data) const
|
||||
return Battlefield::GetData(data);
|
||||
}
|
||||
|
||||
void BattlefieldWG::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlefieldWG::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_ATTACKER) << uint32(GetAttackerTeam());
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_DEFENDER) << uint32(GetDefenderTeam());
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_ACTIVE) << uint32(IsWarTime() ? 0 : 1); // Note: cleanup these two, their names look awkward
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_SHOW_WORLDSTATE) << uint32(IsWarTime() ? 1 : 0);
|
||||
packet.Worldstates.reserve(4+2+WG_MAX_OBJ+WG_MAX_WORKSHOP);
|
||||
packet.Worldstates.emplace_back(BATTLEFIELD_WG_WORLD_STATE_ATTACKER, GetAttackerTeam());
|
||||
packet.Worldstates.emplace_back(BATTLEFIELD_WG_WORLD_STATE_DEFENDER, GetDefenderTeam());
|
||||
|
||||
// Note: cleanup these two, their names look awkward
|
||||
packet.Worldstates.emplace_back(BATTLEFIELD_WG_WORLD_STATE_ACTIVE, IsWarTime() ? 0 : 1);
|
||||
packet.Worldstates.emplace_back(BATTLEFIELD_WG_WORLD_STATE_SHOW_WORLDSTATE, IsWarTime() ? 1 : 0);
|
||||
|
||||
for (uint32 i = 0; i < 2; ++i)
|
||||
data << ClockWorldState[i] << uint32(GameTime::GetGameTime().count() + (m_Timer / 1000));
|
||||
packet.Worldstates.emplace_back(ClockWorldState[i], GameTime::GetGameTime().count() + (m_Timer / 1000));
|
||||
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_VEHICLE_H) << uint32(GetData(BATTLEFIELD_WG_DATA_VEHICLE_H));
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_MAX_VEHICLE_H) << GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H);
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_VEHICLE_A) << uint32(GetData(BATTLEFIELD_WG_DATA_VEHICLE_A));
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_MAX_VEHICLE_A) << GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A);
|
||||
packet.Worldstates.emplace_back(BATTLEFIELD_WG_WORLD_STATE_VEHICLE_H, GetData(BATTLEFIELD_WG_DATA_VEHICLE_H));
|
||||
packet.Worldstates.emplace_back(BATTLEFIELD_WG_WORLD_STATE_MAX_VEHICLE_H, GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H));
|
||||
packet.Worldstates.emplace_back(BATTLEFIELD_WG_WORLD_STATE_VEHICLE_A, GetData(BATTLEFIELD_WG_DATA_VEHICLE_A));
|
||||
packet.Worldstates.emplace_back(BATTLEFIELD_WG_WORLD_STATE_MAX_VEHICLE_A, GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A));
|
||||
|
||||
data << uint32(WORLDSTATE_HORDE_KEEP_CAPTURED) << uint32(sWorld->getWorldState(WORLDSTATE_HORDE_KEEP_CAPTURED));
|
||||
data << uint32(WORLDSTATE_HORDE_KEEP_DEFENDED) << uint32(sWorld->getWorldState(WORLDSTATE_HORDE_KEEP_DEFENDED));
|
||||
data << uint32(WORLDSTATE_ALLIANCE_KEEP_CAPTURED) << uint32(sWorld->getWorldState(WORLDSTATE_ALLIANCE_KEEP_CAPTURED));
|
||||
data << uint32(WORLDSTATE_ALLIANCE_KEEP_DEFENDED) << uint32(sWorld->getWorldState(WORLDSTATE_ALLIANCE_KEEP_DEFENDED));
|
||||
packet.Worldstates.emplace_back(WORLDSTATE_ALLIANCE_KEEP_DEFENDED, uint32(sWorld->getWorldState(WORLDSTATE_ALLIANCE_KEEP_DEFENDED)));
|
||||
packet.Worldstates.emplace_back(WORLDSTATE_HORDE_KEEP_CAPTURED, uint32(sWorld->getWorldState(WORLDSTATE_HORDE_KEEP_CAPTURED)));
|
||||
packet.Worldstates.emplace_back(WORLDSTATE_HORDE_KEEP_DEFENDED, uint32(sWorld->getWorldState(WORLDSTATE_HORDE_KEEP_DEFENDED)));
|
||||
packet.Worldstates.emplace_back(WORLDSTATE_ALLIANCE_KEEP_CAPTURED, uint32(sWorld->getWorldState(WORLDSTATE_ALLIANCE_KEEP_CAPTURED)));
|
||||
|
||||
for (GameObjectBuilding::const_iterator itr = BuildingsInZone.begin(); itr != BuildingsInZone.end(); ++itr)
|
||||
data << (*itr)->m_WorldState << (*itr)->m_State;
|
||||
packet.Worldstates.emplace_back((*itr)->m_WorldState, (*itr)->m_State);
|
||||
|
||||
for (Workshop::const_iterator itr = WorkshopsList.begin(); itr != WorkshopsList.end(); ++itr)
|
||||
if (*itr)
|
||||
data << WorkshopsData[(*itr)->workshopId].worldstate << (*itr)->state;
|
||||
packet.Worldstates.emplace_back(WorkshopsData[(*itr)->workshopId].worldstate, (*itr)->state);
|
||||
}
|
||||
|
||||
void BattlefieldWG::SendInitWorldStatesTo(Player* player)
|
||||
{
|
||||
WorldPacket data(SMSG_INIT_WORLD_STATES, (4 + 4 + 4 + 2 + (BuildingsInZone.size() * 8) + (WorkshopsList.size() * 8)));
|
||||
WorldPackets::WorldState::InitWorldStates packet;
|
||||
packet.MapID = m_MapId;
|
||||
packet.ZoneID = m_ZoneId;
|
||||
packet.AreaID = player->GetAreaId();
|
||||
FillInitialWorldStates(packet);
|
||||
|
||||
data << uint32(m_MapId);
|
||||
data << uint32(m_ZoneId);
|
||||
data << uint32(0);
|
||||
data << uint16(14 + BuildingsInZone.size() + WorkshopsList.size()); // Number of fields
|
||||
|
||||
FillInitialWorldStates(data);
|
||||
|
||||
player->GetSession()->SendPacket(&data);
|
||||
player->SendDirectMessage(packet.Write());
|
||||
}
|
||||
|
||||
void BattlefieldWG::SendInitWorldStatesToAll()
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "Battlefield.h"
|
||||
#include "Log.h"
|
||||
#include "World.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
class Group;
|
||||
class BattlefieldWG;
|
||||
@@ -238,7 +239,7 @@ const uint32 WGQuest[2][6] =
|
||||
{ 13185, 13183, 13223, 13539, 13178, 13180 },
|
||||
};
|
||||
// 7 in sql, 7 in header
|
||||
const BfWGCoordGY WGGraveYard[BATTLEFIELD_WG_GRAVEYARD_MAX] =
|
||||
const BfWGCoordGY WGGraveyard[BATTLEFIELD_WG_GRAVEYARD_MAX] =
|
||||
{
|
||||
{ 5104.750f, 2300.940f, 368.579f, 0.733038f, 1329, BATTLEFIELD_WG_GY_WORKSHOP_NE, BATTLEFIELD_WG_GOSSIPTEXT_GY_NE, TEAM_NEUTRAL },
|
||||
{ 5099.120f, 3466.036f, 368.484f, 5.317802f, 1330, BATTLEFIELD_WG_GY_WORKSHOP_NW, BATTLEFIELD_WG_GOSSIPTEXT_GY_NW, TEAM_NEUTRAL },
|
||||
@@ -403,7 +404,7 @@ public:
|
||||
|
||||
void SendInitWorldStatesTo(Player* player);
|
||||
void SendInitWorldStatesToAll() override;
|
||||
void FillInitialWorldStates(WorldPacket& data) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
|
||||
void HandleKill(Player* killer, Unit* victim) override;
|
||||
void OnUnitDeath(Unit* unit) override;
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
//#include "WorldStatePackets.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
void ArenaScore::AppendToPacket(WorldPacket& data)
|
||||
{
|
||||
@@ -146,10 +147,11 @@ void Arena::RemovePlayer(Player* /*player*/)
|
||||
CheckWinConditions();
|
||||
}
|
||||
|
||||
void Arena::FillInitialWorldStates(WorldPacket& data)
|
||||
void Arena::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(ARENA_WORLD_STATE_ALIVE_PLAYERS_GREEN) << uint32(GetAlivePlayersCountByTeam(TEAM_HORDE));
|
||||
data << uint32(ARENA_WORLD_STATE_ALIVE_PLAYERS_GOLD) << uint32(GetAlivePlayersCountByTeam(TEAM_ALLIANCE));
|
||||
packet.Worldstates.reserve(2);
|
||||
packet.Worldstates.emplace_back(ARENA_WORLD_STATE_ALIVE_PLAYERS_GREEN, GetAlivePlayersCountByTeam(TEAM_HORDE));
|
||||
packet.Worldstates.emplace_back(ARENA_WORLD_STATE_ALIVE_PLAYERS_GOLD, GetAlivePlayersCountByTeam(TEAM_ALLIANCE));
|
||||
}
|
||||
|
||||
void Arena::UpdateArenaWorldState()
|
||||
@@ -224,7 +226,7 @@ void Arena::EndBattleground(TeamId winnerTeamId)
|
||||
{
|
||||
// pussywizard: arena logs in database
|
||||
uint32 fightId = sArenaTeamMgr->GetNextArenaLogId();
|
||||
uint32 currOnline = sWorld->GetActiveSessionCount();
|
||||
uint32 currOnline = sWorldSessionMgr->GetActiveSessionCount();
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabasePreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_LOG_FIGHT);
|
||||
|
||||
@@ -52,7 +52,7 @@ protected:
|
||||
void AddPlayer(Player* player) override;
|
||||
void RemovePlayer(Player* /*player*/) override;
|
||||
|
||||
void FillInitialWorldStates(WorldPacket& data) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
void UpdateArenaWorldState();
|
||||
|
||||
void HandleKillPlayer(Player* player, Player* killer) override;
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ArenaSeasonMgr.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "ArenaSeasonRewardsDistributor.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "GameEventMgr.h"
|
||||
#include "MapMgr.h"
|
||||
#include "Player.h"
|
||||
|
||||
ArenaSeasonMgr* ArenaSeasonMgr::instance()
|
||||
{
|
||||
static ArenaSeasonMgr instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void ArenaSeasonMgr::LoadRewards()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
std::unordered_map<std::string, ArenaSeasonRewardGroupCriteriaType> stringToArenaSeasonRewardGroupCriteriaType = {
|
||||
{"pct", ArenaSeasonRewardGroupCriteriaType::ARENA_SEASON_REWARD_CRITERIA_TYPE_PERCENT_VALUE},
|
||||
{"abs", ArenaSeasonRewardGroupCriteriaType::ARENA_SEASON_REWARD_CRITERIA_TYPE_ABSOLUTE_VALUE}
|
||||
};
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT id, arena_season, criteria_type, min_criteria, max_criteria, reward_mail_template_id, reward_mail_subject, reward_mail_body, gold_reward FROM arena_season_reward_group");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 arena season rewards. DB table `arena_season_reward_group` is empty.");
|
||||
LOG_INFO("server.loading", " ");
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_map<uint32, ArenaSeasonRewardGroup> groupsMap;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 id = fields[0].Get<uint32>();
|
||||
|
||||
ArenaSeasonRewardGroup group;
|
||||
group.season = fields[1].Get<uint8>();
|
||||
group.criteriaType = stringToArenaSeasonRewardGroupCriteriaType[fields[2].Get<std::string>()];
|
||||
group.minCriteria = fields[3].Get<float>();
|
||||
group.maxCriteria = fields[4].Get<float>();
|
||||
group.rewardMailTemplateID = fields[5].Get<uint32>();
|
||||
group.rewardMailSubject = fields[6].Get<std::string>();
|
||||
group.rewardMailBody = fields[7].Get<std::string>();
|
||||
group.goldReward = fields[8].Get<uint32>();
|
||||
|
||||
groupsMap[id] = group;
|
||||
} while (result->NextRow());
|
||||
|
||||
std::unordered_map<std::string, ArenaSeasonRewardType> stringToArenaSeasonRewardType = {
|
||||
{"achievement", ArenaSeasonRewardType::ARENA_SEASON_REWARD_TYPE_ACHIEVEMENT},
|
||||
{"item", ArenaSeasonRewardType::ARENA_SEASON_REWARD_TYPE_ITEM}
|
||||
};
|
||||
|
||||
result = WorldDatabase.Query("SELECT group_id, type, entry FROM arena_season_reward");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 arena season rewards. DB table `arena_season_reward` is empty.");
|
||||
LOG_INFO("server.loading", " ");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 groupId = fields[0].Get<uint32>();
|
||||
|
||||
ArenaSeasonReward reward;
|
||||
reward.type = stringToArenaSeasonRewardType[fields[1].Get<std::string>()];
|
||||
reward.entry = fields[2].Get<uint32>();
|
||||
|
||||
auto itr = groupsMap.find(groupId);
|
||||
ASSERT(itr != groupsMap.end(), "Unknown arena_season_reward_group ({}) in arena_season_reward", groupId);
|
||||
|
||||
(reward.type == ARENA_SEASON_REWARD_TYPE_ITEM) ?
|
||||
groupsMap[groupId].itemRewards.push_back(reward) :
|
||||
groupsMap[groupId].achievementRewards.push_back(reward);
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
for (auto const& itr : groupsMap)
|
||||
_arenaSeasonRewardGroupsStore[itr.second.season].push_back(itr.second);
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} arena season rewards in {} ms", (uint32)groupsMap.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void ArenaSeasonMgr::LoadActiveSeason()
|
||||
{
|
||||
QueryResult result = CharacterDatabase.Query("SELECT season_id, season_state FROM active_arena_season");
|
||||
ASSERT(result, "active_arena_season can't be empty");
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
_currentSeason = fields[0].Get<uint8>();
|
||||
_currentSeasonState = static_cast<ArenaSeasonState>(fields[1].Get<uint8>());
|
||||
|
||||
uint16 eventID = GameEventForArenaSeason(_currentSeason);
|
||||
sGameEventMgr->StartEvent(eventID, true);
|
||||
|
||||
LOG_INFO("server.loading", "Arena Season {} loaded...", _currentSeason);
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void ArenaSeasonMgr::RewardTeamsForTheSeason(std::shared_ptr<ArenaTeamFilter> teamsFilter)
|
||||
{
|
||||
ArenaSeasonTeamRewarderImpl rewarder = ArenaSeasonTeamRewarderImpl();
|
||||
ArenaSeasonRewardDistributor distributor = ArenaSeasonRewardDistributor(&rewarder);
|
||||
std::vector<ArenaSeasonRewardGroup> rewards = _arenaSeasonRewardGroupsStore[GetCurrentSeason()];
|
||||
ArenaTeamMgr::ArenaTeamContainer filteredTeams = teamsFilter->Filter(sArenaTeamMgr->GetArenaTeams());
|
||||
distributor.DistributeRewards(filteredTeams, rewards);
|
||||
}
|
||||
|
||||
bool ArenaSeasonMgr::CanDeleteArenaTeams()
|
||||
{
|
||||
std::vector<ArenaSeasonRewardGroup> rewards = _arenaSeasonRewardGroupsStore[GetCurrentSeason()];
|
||||
if (rewards.empty())
|
||||
return false;
|
||||
|
||||
for (auto const& bg : sBattlegroundMgr->GetActiveBattlegrounds())
|
||||
if (bg->isRated())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArenaSeasonMgr::DeleteArenaTeams()
|
||||
{
|
||||
if (!CanDeleteArenaTeams())
|
||||
return;
|
||||
|
||||
// Cleanup queue first.
|
||||
std::vector<BattlegroundQueueTypeId> arenasQueueTypes = {BATTLEGROUND_QUEUE_2v2, BATTLEGROUND_QUEUE_3v3, BATTLEGROUND_QUEUE_5v5};
|
||||
for (BattlegroundQueueTypeId queueType : arenasQueueTypes)
|
||||
{
|
||||
auto queue = sBattlegroundMgr->GetBattlegroundQueue(queueType);
|
||||
for (auto const& [playerGUID, other] : queue.m_QueuedPlayers)
|
||||
queue.RemovePlayer(playerGUID, true);
|
||||
}
|
||||
|
||||
sArenaTeamMgr->DeleteAllArenaTeams();
|
||||
}
|
||||
|
||||
void ArenaSeasonMgr::ChangeCurrentSeason(uint8 season)
|
||||
{
|
||||
if (_currentSeason == season)
|
||||
return;
|
||||
|
||||
uint16 currentEventID = GameEventForArenaSeason(_currentSeason);
|
||||
sGameEventMgr->StopEvent(currentEventID, true);
|
||||
|
||||
uint16 newEventID = GameEventForArenaSeason(season);
|
||||
sGameEventMgr->StartEvent(newEventID, true);
|
||||
|
||||
_currentSeason = season;
|
||||
_currentSeasonState = ARENA_SEASON_STATE_IN_PROGRESS;
|
||||
|
||||
CharacterDatabase.Execute("UPDATE active_arena_season SET season_id = {}, season_state = {}", _currentSeason, _currentSeasonState);
|
||||
|
||||
BroadcastUpdatedWorldState();
|
||||
}
|
||||
|
||||
void ArenaSeasonMgr::SetSeasonState(ArenaSeasonState state)
|
||||
{
|
||||
if (_currentSeasonState == state)
|
||||
return;
|
||||
|
||||
_currentSeasonState = state;
|
||||
|
||||
CharacterDatabase.Execute("UPDATE active_arena_season SET season_state = {}", _currentSeasonState);
|
||||
|
||||
BroadcastUpdatedWorldState();
|
||||
}
|
||||
|
||||
uint16 ArenaSeasonMgr::GameEventForArenaSeason(uint8 season)
|
||||
{
|
||||
QueryResult result = WorldDatabase.Query("SELECT eventEntry FROM game_event_arena_seasons WHERE season = '{}'", season);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_ERROR("arenaseasonmgr", "ArenaSeason ({}) must be an existant Arena Season", season);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
return fields[0].Get<uint16>();
|
||||
}
|
||||
|
||||
void ArenaSeasonMgr::BroadcastUpdatedWorldState()
|
||||
{
|
||||
sMapMgr->DoForAllMaps([](Map* map)
|
||||
{
|
||||
// Ignore instanceable maps, players will get a fresh state once they change the map.
|
||||
if (map->Instanceable())
|
||||
return;
|
||||
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
uint32 currZone, currArea;
|
||||
player->GetZoneAndAreaId(currZone, currArea);
|
||||
player->SendInitWorldStates(currZone, currArea);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ARENASEASONMGR_H
|
||||
#define _ARENASEASONMGR_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "ArenaTeamFilter.h"
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
enum ArenaSeasonState
|
||||
{
|
||||
ARENA_SEASON_STATE_DISABLED = 0,
|
||||
ARENA_SEASON_STATE_IN_PROGRESS = 1
|
||||
};
|
||||
|
||||
enum ArenaSeasonRewardType
|
||||
{
|
||||
ARENA_SEASON_REWARD_TYPE_ITEM,
|
||||
ARENA_SEASON_REWARD_TYPE_ACHIEVEMENT
|
||||
};
|
||||
|
||||
enum ArenaSeasonRewardGroupCriteriaType
|
||||
{
|
||||
ARENA_SEASON_REWARD_CRITERIA_TYPE_PERCENT_VALUE,
|
||||
ARENA_SEASON_REWARD_CRITERIA_TYPE_ABSOLUTE_VALUE
|
||||
};
|
||||
|
||||
// ArenaSeasonReward represents one reward, it can be an item or achievement.
|
||||
struct ArenaSeasonReward
|
||||
{
|
||||
ArenaSeasonReward() = default;
|
||||
|
||||
// Item or acheivement entry.
|
||||
uint32 entry{};
|
||||
|
||||
ArenaSeasonRewardType type{ARENA_SEASON_REWARD_TYPE_ITEM};
|
||||
|
||||
// Used in unit tests.
|
||||
bool operator==(const ArenaSeasonReward& other) const
|
||||
{
|
||||
return entry == other.entry && type == other.type;
|
||||
}
|
||||
};
|
||||
|
||||
struct ArenaSeasonRewardGroup
|
||||
{
|
||||
ArenaSeasonRewardGroup() = default;
|
||||
|
||||
uint8 season{};
|
||||
|
||||
ArenaSeasonRewardGroupCriteriaType criteriaType;
|
||||
|
||||
float minCriteria{};
|
||||
float maxCriteria{};
|
||||
|
||||
uint32 rewardMailTemplateID{};
|
||||
std::string rewardMailSubject{};
|
||||
std::string rewardMailBody{};
|
||||
uint32 goldReward{};
|
||||
|
||||
std::vector<ArenaSeasonReward> itemRewards;
|
||||
std::vector<ArenaSeasonReward> achievementRewards;
|
||||
|
||||
// Used in unit tests.
|
||||
bool operator==(const ArenaSeasonRewardGroup& other) const
|
||||
{
|
||||
return minCriteria == other.minCriteria &&
|
||||
maxCriteria == other.maxCriteria &&
|
||||
criteriaType == other.criteriaType &&
|
||||
itemRewards == other.itemRewards &&
|
||||
achievementRewards == other.achievementRewards;
|
||||
}
|
||||
};
|
||||
|
||||
class ArenaSeasonMgr
|
||||
{
|
||||
public:
|
||||
static ArenaSeasonMgr* instance();
|
||||
|
||||
using ArenaSeasonRewardGroupsBySeasonContainer = std::unordered_map<uint8, std::vector<ArenaSeasonRewardGroup>>;
|
||||
|
||||
// Loading functions
|
||||
void LoadRewards();
|
||||
void LoadActiveSeason();
|
||||
|
||||
// Season management functions
|
||||
void ChangeCurrentSeason(uint8 season);
|
||||
uint8 GetCurrentSeason() { return _currentSeason; }
|
||||
|
||||
void SetSeasonState(ArenaSeasonState state);
|
||||
ArenaSeasonState GetSeasonState() { return _currentSeasonState; }
|
||||
|
||||
// Season completion functions
|
||||
void RewardTeamsForTheSeason(std::shared_ptr<ArenaTeamFilter> teamsFilter);
|
||||
bool CanDeleteArenaTeams();
|
||||
void DeleteArenaTeams();
|
||||
|
||||
private:
|
||||
uint16 GameEventForArenaSeason(uint8 season);
|
||||
void BroadcastUpdatedWorldState();
|
||||
|
||||
ArenaSeasonRewardGroupsBySeasonContainer _arenaSeasonRewardGroupsStore;
|
||||
|
||||
uint8 _currentSeason{};
|
||||
ArenaSeasonState _currentSeasonState{};
|
||||
};
|
||||
|
||||
#define sArenaSeasonMgr ArenaSeasonMgr::instance()
|
||||
|
||||
#endif // _ARENASEASONMGR_H
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ArenaSeasonRewardsDistributor.h"
|
||||
#include "AchievementMgr.h"
|
||||
#include "CharacterDatabase.h"
|
||||
#include "Mail.h"
|
||||
#include "Player.h"
|
||||
#include <algorithm>
|
||||
|
||||
constexpr float minPctTeamGamesForMemberToGetReward = 30;
|
||||
|
||||
void ArenaSeasonTeamRewarderImpl::RewardTeamWithRewardGroup(ArenaTeam *arenaTeam, const ArenaSeasonRewardGroup &rewardGroup)
|
||||
{
|
||||
RewardWithMail(arenaTeam, rewardGroup);
|
||||
RewardWithAchievements(arenaTeam, rewardGroup);
|
||||
}
|
||||
|
||||
void ArenaSeasonTeamRewarderImpl::RewardWithMail(ArenaTeam* arenaTeam, ArenaSeasonRewardGroup const & rewardGroup)
|
||||
{
|
||||
if (rewardGroup.itemRewards.empty() && rewardGroup.goldReward == 0)
|
||||
return;
|
||||
|
||||
const uint32 npcKingDondSender = 18897;
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
for (auto const& member : arenaTeam->GetMembers())
|
||||
{
|
||||
uint32 teamSeasonGames = arenaTeam->GetStats().SeasonGames;
|
||||
// Avoid division by zero.
|
||||
if (teamSeasonGames == 0)
|
||||
continue;
|
||||
|
||||
float memberParticipationPercentage = (static_cast<float>(member.SeasonGames) / teamSeasonGames) * 100;
|
||||
if (memberParticipationPercentage < minPctTeamGamesForMemberToGetReward)
|
||||
continue;
|
||||
|
||||
Player* player = ObjectAccessor::FindPlayer(member.Guid);
|
||||
|
||||
auto draft = rewardGroup.rewardMailTemplateID > 0 ?
|
||||
MailDraft(rewardGroup.rewardMailTemplateID, false) :
|
||||
MailDraft(rewardGroup.rewardMailSubject, rewardGroup.rewardMailBody);
|
||||
|
||||
if (rewardGroup.goldReward > 0)
|
||||
draft.AddMoney(rewardGroup.goldReward);
|
||||
|
||||
for (auto const& reward : rewardGroup.itemRewards)
|
||||
if (Item* item = Item::CreateItem(reward.entry, 1))
|
||||
{
|
||||
item->SaveToDB(trans);
|
||||
draft.AddItem(item);
|
||||
}
|
||||
|
||||
draft.SendMailTo(trans, MailReceiver(player, member.Guid.GetCounter()), MailSender(npcKingDondSender));
|
||||
}
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void ArenaSeasonTeamRewarderImpl::RewardWithAchievements(ArenaTeam* arenaTeam, ArenaSeasonRewardGroup const & rewardGroup)
|
||||
{
|
||||
if (rewardGroup.achievementRewards.empty())
|
||||
return;
|
||||
|
||||
for (auto const& member : arenaTeam->GetMembers())
|
||||
{
|
||||
uint32 teamSeasonGames = arenaTeam->GetStats().SeasonGames;
|
||||
// Avoid division by zero.
|
||||
if (teamSeasonGames == 0)
|
||||
continue;
|
||||
|
||||
float memberParticipationPercentage = (static_cast<float>(member.SeasonGames) / teamSeasonGames) * 100;
|
||||
if (memberParticipationPercentage < minPctTeamGamesForMemberToGetReward)
|
||||
continue;
|
||||
|
||||
Player* player = ObjectAccessor::FindPlayer(member.Guid);
|
||||
for (auto const& reward : rewardGroup.achievementRewards)
|
||||
{
|
||||
AchievementEntry const* achievement = sAchievementStore.LookupEntry(reward.entry);
|
||||
if (!achievement)
|
||||
continue;
|
||||
|
||||
if (player)
|
||||
player->CompletedAchievement(achievement);
|
||||
else
|
||||
sAchievementMgr->CompletedAchievementForOfflinePlayer(member.Guid.GetCounter(), achievement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArenaSeasonRewardDistributor::ArenaSeasonRewardDistributor(ArenaSeasonTeamRewarder* rewarder)
|
||||
: _rewarder(rewarder)
|
||||
{
|
||||
}
|
||||
|
||||
void ArenaSeasonRewardDistributor::DistributeRewards(ArenaTeamMgr::ArenaTeamContainer &arenaTeams, std::vector<ArenaSeasonRewardGroup> &rewardGroups)
|
||||
{
|
||||
std::vector<ArenaTeam*> sortedTeams;
|
||||
sortedTeams.reserve(arenaTeams.size());
|
||||
|
||||
static constexpr uint16 minRequiredGames = 30;
|
||||
|
||||
for (auto const& [id, team] : arenaTeams)
|
||||
if (team->GetStats().SeasonGames >= minRequiredGames)
|
||||
sortedTeams.push_back(team);
|
||||
|
||||
std::sort(sortedTeams.begin(), sortedTeams.end(), [](ArenaTeam* a, ArenaTeam* b) {
|
||||
return a->GetRating() > b->GetRating();
|
||||
});
|
||||
|
||||
std::vector<ArenaSeasonRewardGroup> pctRewardGroup;
|
||||
std::vector<ArenaSeasonRewardGroup> absRewardGroup;
|
||||
|
||||
for (auto const& reward : rewardGroups)
|
||||
{
|
||||
if (reward.criteriaType == ARENA_SEASON_REWARD_CRITERIA_TYPE_PERCENT_VALUE)
|
||||
pctRewardGroup.push_back(reward);
|
||||
else
|
||||
absRewardGroup.push_back(reward);
|
||||
}
|
||||
|
||||
size_t totalTeams = sortedTeams.size();
|
||||
for (auto const& rewardGroup : pctRewardGroup)
|
||||
{
|
||||
size_t minIndex = static_cast<size_t>(rewardGroup.minCriteria * totalTeams / 100);
|
||||
size_t maxIndex = static_cast<size_t>(rewardGroup.maxCriteria * totalTeams / 100);
|
||||
|
||||
minIndex = std::min(minIndex, totalTeams);
|
||||
maxIndex = std::min(maxIndex, totalTeams);
|
||||
|
||||
for (size_t i = minIndex; i < maxIndex; ++i)
|
||||
{
|
||||
ArenaTeam* team = sortedTeams[i];
|
||||
_rewarder->RewardTeamWithRewardGroup(team, rewardGroup);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& rewardGroup : absRewardGroup)
|
||||
{
|
||||
size_t minIndex = rewardGroup.minCriteria-1; // Top 1 team is the team with index 0, so we need make -1.
|
||||
size_t maxIndex = rewardGroup.maxCriteria;
|
||||
|
||||
minIndex = std::max(minIndex, size_t(0));
|
||||
minIndex = std::min(minIndex, totalTeams);
|
||||
maxIndex = std::min(maxIndex, totalTeams);
|
||||
|
||||
for (size_t i = minIndex; i < maxIndex; ++i)
|
||||
{
|
||||
ArenaTeam* team = sortedTeams[i];
|
||||
_rewarder->RewardTeamWithRewardGroup(team, rewardGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ARENASEASONREWARDDISTRIBUTOR_H
|
||||
#define _ARENASEASONREWARDDISTRIBUTOR_H
|
||||
|
||||
#include "ArenaSeasonMgr.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
|
||||
class ArenaSeasonTeamRewarder
|
||||
{
|
||||
public:
|
||||
virtual ~ArenaSeasonTeamRewarder() = default;
|
||||
|
||||
virtual void RewardTeamWithRewardGroup(ArenaTeam* arenaTeam, ArenaSeasonRewardGroup const & rewardGroup) = 0;
|
||||
};
|
||||
|
||||
class ArenaSeasonTeamRewarderImpl: public ArenaSeasonTeamRewarder
|
||||
{
|
||||
public:
|
||||
void RewardTeamWithRewardGroup(ArenaTeam* arenaTeam, ArenaSeasonRewardGroup const & rewardGroup) override;
|
||||
|
||||
private:
|
||||
void RewardWithMail(ArenaTeam* arenaTeam, ArenaSeasonRewardGroup const & rewardGroup);
|
||||
void RewardWithAchievements(ArenaTeam* arenaTeam, ArenaSeasonRewardGroup const & rewardGroup);
|
||||
};
|
||||
|
||||
class ArenaSeasonRewardDistributor
|
||||
{
|
||||
public:
|
||||
ArenaSeasonRewardDistributor(ArenaSeasonTeamRewarder* rewarder);
|
||||
|
||||
void DistributeRewards(ArenaTeamMgr::ArenaTeamContainer& arenaTeams, std::vector<ArenaSeasonRewardGroup>& rewardGroups);
|
||||
|
||||
private:
|
||||
ArenaSeasonTeamRewarder* _rewarder;
|
||||
};
|
||||
|
||||
#endif // _ARENASEASONREWARDDISTRIBUTOR_H
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ARENATEAMFILTER_H
|
||||
#define _ARENATEAMFILTER_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "Tokenize.h"
|
||||
#include "StringConvert.h"
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
class ArenaTeamFilter
|
||||
{
|
||||
public:
|
||||
virtual ~ArenaTeamFilter() = default;
|
||||
|
||||
virtual ArenaTeamMgr::ArenaTeamContainer Filter(ArenaTeamMgr::ArenaTeamContainer teams) = 0;
|
||||
};
|
||||
|
||||
class ArenaTeamFilterByTypes : public ArenaTeamFilter
|
||||
{
|
||||
public:
|
||||
ArenaTeamFilterByTypes(std::vector<uint8> validTypes) : _validTypes(validTypes) {}
|
||||
|
||||
ArenaTeamMgr::ArenaTeamContainer Filter(ArenaTeamMgr::ArenaTeamContainer teams) override
|
||||
{
|
||||
ArenaTeamMgr::ArenaTeamContainer result;
|
||||
|
||||
for (auto const& pair : teams)
|
||||
{
|
||||
ArenaTeam* team = pair.second;
|
||||
for (uint8 arenaType : _validTypes)
|
||||
{
|
||||
if (team->GetType() == arenaType)
|
||||
{
|
||||
result[pair.first] = team;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8> _validTypes;
|
||||
};
|
||||
|
||||
class ArenaTeamFilterAllTeams : public ArenaTeamFilter
|
||||
{
|
||||
public:
|
||||
ArenaTeamMgr::ArenaTeamContainer Filter(ArenaTeamMgr::ArenaTeamContainer teams) override
|
||||
{
|
||||
return teams;
|
||||
}
|
||||
};
|
||||
|
||||
class ArenaTeamFilterFactoryByUserInput
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<ArenaTeamFilter> CreateFilterByUserInput(std::string userInput)
|
||||
{
|
||||
std::transform(userInput.begin(), userInput.end(), userInput.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
|
||||
if (userInput == "all")
|
||||
return std::make_unique<ArenaTeamFilterAllTeams>();
|
||||
|
||||
// Parse the input string (e.g., "2,3") into valid types
|
||||
std::vector<uint8> validTypes = ParseTypes(userInput);
|
||||
|
||||
if (!validTypes.empty())
|
||||
return std::make_unique<ArenaTeamFilterByTypes>(validTypes);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8> ParseTypes(std::string_view userInput)
|
||||
{
|
||||
std::vector<uint8> validTypes;
|
||||
auto tokens = Acore::Tokenize(userInput, ',', false);
|
||||
|
||||
for (auto const& token : tokens)
|
||||
if (auto typeOpt = Acore::StringTo<uint8>(token))
|
||||
validTypes.push_back(*typeOpt);
|
||||
|
||||
return validTypes;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _ARENATEAMFILTER_H
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "ArenaTeam.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "ArenaSeasonMgr.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "CharacterCache.h"
|
||||
#include "Group.h"
|
||||
@@ -658,7 +659,7 @@ uint32 ArenaTeam::GetPoints(uint32 memberRating)
|
||||
|
||||
if (rating <= 1500)
|
||||
{
|
||||
if (sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) < 6 && !sWorld->getIntConfig(CONFIG_LEGACY_ARENA_POINTS_CALC))
|
||||
if (sArenaSeasonMgr->GetCurrentSeason() < 6 && !sWorld->getIntConfig(CONFIG_LEGACY_ARENA_POINTS_CALC))
|
||||
points = (float)rating * 0.22f + 14.0f;
|
||||
else
|
||||
points = 344;
|
||||
|
||||
@@ -125,6 +125,27 @@ void ArenaTeamMgr::RemoveArenaTeam(uint32 arenaTeamId)
|
||||
ArenaTeamStore.erase(arenaTeamId);
|
||||
}
|
||||
|
||||
void ArenaTeamMgr::DeleteAllArenaTeams()
|
||||
{
|
||||
for (auto const& [id, team] : ArenaTeamStore)
|
||||
{
|
||||
while (team->GetMembersSize() > 0)
|
||||
team->DelMember(team->GetMembers().front().Guid, false);
|
||||
|
||||
delete team;
|
||||
}
|
||||
|
||||
ArenaTeamStore.clear();
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
trans->Append("DELETE FROM arena_team_member");
|
||||
trans->Append("DELETE FROM arena_team");
|
||||
trans->Append("DELETE FROM character_arena_stats");
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
NextArenaTeamId = 1;
|
||||
}
|
||||
|
||||
uint32 ArenaTeamMgr::GenerateArenaTeamId()
|
||||
{
|
||||
if (NextArenaTeamId >= MAX_ARENA_TEAM_ID)
|
||||
|
||||
@@ -43,6 +43,8 @@ public:
|
||||
void AddArenaTeam(ArenaTeam* arenaTeam);
|
||||
void RemoveArenaTeam(uint32 Id);
|
||||
|
||||
void DeleteAllArenaTeams();
|
||||
|
||||
ArenaTeamContainer::iterator GetArenaTeamMapBegin() { return ArenaTeamStore.begin(); }
|
||||
ArenaTeamContainer::iterator GetArenaTeamMapEnd() { return ArenaTeamStore.end(); }
|
||||
ArenaTeamContainer& GetArenaTeams() { return ArenaTeamStore; }
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "GameObject.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "World.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
class Creature;
|
||||
class GameObject;
|
||||
@@ -458,7 +459,7 @@ public:
|
||||
|
||||
// Packet Transfer
|
||||
// method that should fill worldpacket with actual world states (not yet implemented for all battlegrounds!)
|
||||
virtual void FillInitialWorldStates(WorldPacket& /*data*/) { }
|
||||
virtual void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& /*packet*/) { }
|
||||
void SendPacketToTeam(TeamId teamId, WorldPacket const* packet, Player* sender = nullptr, bool self = true);
|
||||
void SendPacketToAll(WorldPacket const* packet);
|
||||
void YellToAll(Creature* creature, const char* text, uint32 language);
|
||||
|
||||
@@ -334,6 +334,18 @@ Battleground* BattlegroundMgr::GetBattlegroundTemplate(BattlegroundTypeId bgType
|
||||
return bgs.empty() ? nullptr : bgs.begin()->second;
|
||||
}
|
||||
|
||||
std::vector<Battleground const*> BattlegroundMgr::GetActiveBattlegrounds()
|
||||
{
|
||||
std::vector<Battleground const*> result;
|
||||
|
||||
for (auto const& [bgType, bgData] : bgDataStore)
|
||||
for (auto const& [id, bg] : bgData._Battlegrounds)
|
||||
if (bg->GetStatus() == STATUS_WAIT_JOIN || bg->GetStatus() == STATUS_IN_PROGRESS)
|
||||
result.push_back(static_cast<const Battleground*>(bg));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 BattlegroundMgr::CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
|
||||
{
|
||||
if (IsArenaType(bgTypeId))
|
||||
|
||||
@@ -82,6 +82,7 @@ public:
|
||||
Battleground* GetBattleground(uint32 instanceID, BattlegroundTypeId bgTypeId);
|
||||
Battleground* GetBattlegroundTemplate(BattlegroundTypeId bgTypeId);
|
||||
Battleground* CreateNewBattleground(BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated);
|
||||
std::vector<Battleground const*> GetActiveBattlegrounds();
|
||||
|
||||
void AddBattleground(Battleground* bg);
|
||||
void RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId);
|
||||
|
||||
@@ -1355,11 +1355,11 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
sScriptMgr->OnBattlegroundDesertion(player, BG_DESERTION_TYPE_NO_ENTER_BUTTON);
|
||||
sScriptMgr->OnPlayerBattlegroundDesertion(player, BG_DESERTION_TYPE_NO_ENTER_BUTTON);
|
||||
}
|
||||
|
||||
if (bg && bg->isArena() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
|
||||
sScriptMgr->OnBattlegroundDesertion(player, ARENA_DESERTION_TYPE_NO_ENTER_BUTTON);
|
||||
sScriptMgr->OnPlayerBattlegroundDesertion(player, ARENA_DESERTION_TYPE_NO_ENTER_BUTTON);
|
||||
|
||||
LOG_DEBUG("bg.battleground", "Battleground: removing player {} from bg queue for instance {} because of not pressing enter battle in time.", player->GetGUID().ToString(), m_BgInstanceGUID);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Util.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
void BattlegroundABScore::BuildObjectivesBlock(WorldPacket& data)
|
||||
{
|
||||
@@ -234,24 +235,26 @@ void BattlegroundAB::DeleteBanner(uint8 node)
|
||||
SpawnBGObject(node * BG_AB_OBJECTS_PER_NODE + BG_AB_OBJECT_AURA_ALLY + _capturePointInfo[node]._ownerTeamId, RESPAWN_ONE_DAY);
|
||||
}
|
||||
|
||||
void BattlegroundAB::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundAB::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
packet.Worldstates.reserve(BG_AB_DYNAMIC_NODES_COUNT+7);
|
||||
for (auto& node : _capturePointInfo)
|
||||
{
|
||||
if (node._state == BG_AB_NODE_STATE_NEUTRAL)
|
||||
data << uint32(node._iconNone) << uint32(1);
|
||||
packet.Worldstates.emplace_back(node._iconNone, 1);
|
||||
|
||||
for (uint8 i = BG_AB_NODE_STATE_ALLY_OCCUPIED; i <= BG_AB_NODE_STATE_HORDE_CONTESTED; ++i)
|
||||
data << uint32(node._iconCapture + i - 1) << uint32(node._state == i);
|
||||
packet.Worldstates.emplace_back(node._iconCapture + i - 1, node._state == i ? 1 : 0);
|
||||
|
||||
}
|
||||
|
||||
data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(_controlledPoints[TEAM_ALLIANCE]);
|
||||
data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(_controlledPoints[TEAM_HORDE]);
|
||||
data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_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[TEAM_ALLIANCE]);
|
||||
data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[TEAM_HORDE]);
|
||||
data << uint32(0x745) << uint32(0x2); // 37 1861 unk
|
||||
packet.Worldstates.emplace_back(BG_AB_OP_OCCUPIED_BASES_ALLY, _controlledPoints[TEAM_ALLIANCE]);
|
||||
packet.Worldstates.emplace_back(BG_AB_OP_OCCUPIED_BASES_HORDE, _controlledPoints[TEAM_HORDE]);
|
||||
packet.Worldstates.emplace_back(BG_AB_OP_RESOURCES_MAX, BG_AB_MAX_TEAM_SCORE);
|
||||
packet.Worldstates.emplace_back(BG_AB_OP_RESOURCES_WARNING, BG_AB_WARNING_NEAR_VICTORY_SCORE);
|
||||
packet.Worldstates.emplace_back(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[TEAM_ALLIANCE]);
|
||||
packet.Worldstates.emplace_back(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[TEAM_HORDE]);
|
||||
packet.Worldstates.emplace_back(0x745, 2);
|
||||
}
|
||||
|
||||
void BattlegroundAB::SendNodeUpdate(uint8 node)
|
||||
|
||||
@@ -316,7 +316,7 @@ public:
|
||||
GraveyardStruct const* GetClosestGraveyard(Player* player) override;
|
||||
|
||||
bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
|
||||
void FillInitialWorldStates(WorldPacket& data) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
void EventPlayerClickedOnFlag(Player* source, GameObject* gameObject) override;
|
||||
|
||||
bool AllNodesConrolledByTeam(TeamId teamId) const override;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Player.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
void BattlegroundAVScore::BuildObjectivesBlock(WorldPacket& data)
|
||||
{
|
||||
@@ -1084,9 +1085,10 @@ void BattlegroundAV::EventPlayerAssaultsPoint(Player* player, uint32 object)
|
||||
player->KilledMonsterCredit((IsTower(node)) ? BG_AV_QUEST_CREDIT_TOWER : BG_AV_QUEST_CREDIT_GRAVEYARD);
|
||||
}
|
||||
|
||||
void BattlegroundAV::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundAV::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
bool stateok;
|
||||
packet.Worldstates.reserve(7*2*2 + 8*2*2 + 5);
|
||||
//graveyards
|
||||
for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; i++)
|
||||
{
|
||||
@@ -1094,8 +1096,8 @@ void BattlegroundAV::FillInitialWorldStates(WorldPacket& data)
|
||||
{
|
||||
//j=1=assaulted j=3=controled
|
||||
stateok = (m_Nodes[i].State == j);
|
||||
data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, TEAM_ALLIANCE)]) << uint32((m_Nodes[i].OwnerId == TEAM_ALLIANCE && stateok) ? 1 : 0);
|
||||
data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, TEAM_HORDE)]) << uint32((m_Nodes[i].OwnerId == TEAM_HORDE && stateok) ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_AV_NodeWorldStates[i][GetWorldStateType(j, TEAM_ALLIANCE)], (m_Nodes[i].OwnerId == TEAM_ALLIANCE && stateok) ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_AV_NodeWorldStates[i][GetWorldStateType(j, TEAM_HORDE)], (m_Nodes[i].OwnerId == TEAM_HORDE && stateok) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1105,23 +1107,19 @@ void BattlegroundAV::FillInitialWorldStates(WorldPacket& data)
|
||||
{
|
||||
//j=1=assaulted j=3=controled //i dont have j=2=destroyed cause destroyed is the same like enemy-team controll
|
||||
stateok = (m_Nodes[i].State == j || (m_Nodes[i].State == POINT_DESTROYED && j == 3));
|
||||
data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, TEAM_ALLIANCE)]) << uint32((m_Nodes[i].OwnerId == TEAM_ALLIANCE && stateok) ? 1 : 0);
|
||||
data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, TEAM_HORDE)]) << uint32((m_Nodes[i].OwnerId == TEAM_HORDE && stateok) ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_AV_NodeWorldStates[i][GetWorldStateType(j, TEAM_ALLIANCE)], (m_Nodes[i].OwnerId == TEAM_ALLIANCE && stateok) ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_AV_NodeWorldStates[i][GetWorldStateType(j, TEAM_HORDE)], (m_Nodes[i].OwnerId == TEAM_HORDE && stateok) ? 1 : 0);
|
||||
}
|
||||
if (m_Nodes[BG_AV_NODES_SNOWFALL_GRAVE].OwnerId == TEAM_NEUTRAL) //cause neutral teams aren't handled generic
|
||||
data << uint32(AV_SNOWFALL_N) << uint32(1);
|
||||
data << uint32(AV_Alliance_Score) << uint32(m_Team_Scores[0]);
|
||||
data << uint32(AV_Horde_Score) << uint32(m_Team_Scores[1]);
|
||||
if (GetStatus() == STATUS_IN_PROGRESS) //only if game started the teamscores are displayed
|
||||
{
|
||||
data << uint32(AV_SHOW_A_SCORE) << uint32(1);
|
||||
data << uint32(AV_SHOW_H_SCORE) << uint32(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(AV_SHOW_A_SCORE) << uint32(0);
|
||||
data << uint32(AV_SHOW_H_SCORE) << uint32(0);
|
||||
packet.Worldstates.emplace_back(AV_SNOWFALL_N, 1);
|
||||
}
|
||||
packet.Worldstates.emplace_back(AV_Alliance_Score, m_Team_Scores[0]);
|
||||
packet.Worldstates.emplace_back(AV_Horde_Score, m_Team_Scores[1]);
|
||||
|
||||
packet.Worldstates.emplace_back(AV_SHOW_A_SCORE, GetStatus() == STATUS_IN_PROGRESS ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(AV_SHOW_H_SCORE, GetStatus() == STATUS_IN_PROGRESS ? 1 : 0);
|
||||
|
||||
SendMineWorldStates(AV_NORTH_MINE);
|
||||
SendMineWorldStates(AV_SOUTH_MINE);
|
||||
}
|
||||
|
||||
@@ -1940,7 +1940,7 @@ private:
|
||||
void ChangeMineOwner(uint8 mine, TeamId teamId, bool initial = false);
|
||||
|
||||
/*worldstates*/
|
||||
void FillInitialWorldStates(WorldPacket& data) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
uint8 GetWorldStateType(uint8 state, TeamId teamId);
|
||||
void SendMineWorldStates(uint32 mine);
|
||||
void UpdateNodeWorldState(BG_AV_Nodes node);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "Log.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
BattlegroundBE::BattlegroundBE()
|
||||
{
|
||||
@@ -87,10 +88,10 @@ void BattlegroundBE::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundBE::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundBE::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(0x9f3) << uint32(1); // 9
|
||||
Arena::FillInitialWorldStates(data);
|
||||
packet.Worldstates.emplace_back(0x9f3, 1); // BATTLEGROUND_BLADES_EDGE_ARENA_SHOW
|
||||
Arena::FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
bool BattlegroundBE::SetupBattleground()
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger) override;
|
||||
bool SetupBattleground() override;
|
||||
void FillInitialWorldStates(WorldPacket& d) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
bool HandlePlayerUnderMap(Player* player) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
BattlegroundDS::BattlegroundDS()
|
||||
{
|
||||
@@ -173,10 +174,10 @@ bool BattlegroundDS::HandlePlayerUnderMap(Player* player)
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundDS::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundDS::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(3610) << uint32(1); // 9 show
|
||||
Arena::FillInitialWorldStates(data);
|
||||
packet.Worldstates.emplace_back(0xe1a, 1); // ARENA_WORLD_STATE_ALIVE_PLAYERS_SHOW
|
||||
Arena::FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
bool BattlegroundDS::SetupBattleground()
|
||||
|
||||
@@ -101,7 +101,7 @@ public:
|
||||
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger) override;
|
||||
bool SetupBattleground() override;
|
||||
void FillInitialWorldStates(WorldPacket& d) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
bool HandlePlayerUnderMap(Player* player) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
void BattlegroundEYScore::BuildObjectivesBlock(WorldPacket& data)
|
||||
{
|
||||
@@ -506,7 +507,7 @@ void BattlegroundEY::EventTeamCapturedPoint(Player* player, TeamId teamId, uint3
|
||||
|
||||
_capturePointInfo[point]._ownerTeamId = teamId;
|
||||
|
||||
GraveyardStruct const* sg = sGraveyard->GetGraveyard(m_CapturingPointTypes[point].GraveYardId);
|
||||
GraveyardStruct const* sg = sGraveyard->GetGraveyard(m_CapturingPointTypes[point].GraveyardId);
|
||||
AddSpiritGuide(point, sg->x, sg->y, sg->z, 3.124139f, teamId);
|
||||
|
||||
UpdatePointsIcons(point);
|
||||
@@ -568,30 +569,31 @@ bool BattlegroundEY::UpdatePlayerScore(Player* player, uint32 type, uint32 value
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundEY::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundEY::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(EY_HORDE_BASE) << uint32(_ownedPointsCount[TEAM_HORDE]);
|
||||
data << uint32(EY_ALLIANCE_BASE) << uint32(_ownedPointsCount[TEAM_ALLIANCE]);
|
||||
data << uint32(DRAENEI_RUINS_HORDE_CONTROL) << uint32(_capturePointInfo[POINT_DRAENEI_RUINS].IsUnderControl(TEAM_HORDE));
|
||||
data << uint32(DRAENEI_RUINS_ALLIANCE_CONTROL) << uint32(_capturePointInfo[POINT_DRAENEI_RUINS].IsUnderControl(TEAM_ALLIANCE));
|
||||
data << uint32(DRAENEI_RUINS_UNCONTROL) << uint32(_capturePointInfo[POINT_DRAENEI_RUINS].IsUncontrolled());
|
||||
data << uint32(MAGE_TOWER_ALLIANCE_CONTROL) << uint32(_capturePointInfo[POINT_MAGE_TOWER].IsUnderControl(TEAM_HORDE));
|
||||
data << uint32(MAGE_TOWER_HORDE_CONTROL) << uint32(_capturePointInfo[POINT_MAGE_TOWER].IsUnderControl(TEAM_ALLIANCE));
|
||||
data << uint32(MAGE_TOWER_UNCONTROL) << uint32(_capturePointInfo[POINT_MAGE_TOWER].IsUncontrolled());
|
||||
data << uint32(FEL_REAVER_HORDE_CONTROL) << uint32(_capturePointInfo[POINT_FEL_REAVER].IsUnderControl(TEAM_HORDE));
|
||||
data << uint32(FEL_REAVER_ALLIANCE_CONTROL) << uint32(_capturePointInfo[POINT_FEL_REAVER].IsUnderControl(TEAM_ALLIANCE));
|
||||
data << uint32(FEL_REAVER_UNCONTROL) << uint32(_capturePointInfo[POINT_FEL_REAVER].IsUncontrolled());
|
||||
data << uint32(BLOOD_ELF_HORDE_CONTROL) << uint32(_capturePointInfo[POINT_BLOOD_ELF].IsUnderControl(TEAM_HORDE));
|
||||
data << uint32(BLOOD_ELF_ALLIANCE_CONTROL) << uint32(_capturePointInfo[POINT_BLOOD_ELF].IsUnderControl(TEAM_ALLIANCE));
|
||||
data << uint32(BLOOD_ELF_UNCONTROL) << uint32(_capturePointInfo[POINT_BLOOD_ELF].IsUncontrolled());
|
||||
data << uint32(NETHERSTORM_FLAG) << uint32(_flagState == BG_EY_FLAG_STATE_ON_BASE);
|
||||
data << uint32(NETHERSTORM_FLAG_STATE_HORDE) << uint32(1);
|
||||
data << uint32(NETHERSTORM_FLAG_STATE_ALLIANCE) << uint32(1);
|
||||
data << uint32(EY_HORDE_RESOURCES) << uint32(GetTeamScore(TEAM_HORDE));
|
||||
data << uint32(EY_ALLIANCE_RESOURCES) << uint32(GetTeamScore(TEAM_ALLIANCE));
|
||||
data << uint32(PROGRESS_BAR_SHOW) << uint32(0);
|
||||
data << uint32(PROGRESS_BAR_PERCENT_GREY) << uint32(0);
|
||||
data << uint32(PROGRESS_BAR_STATUS) << uint32(0);
|
||||
packet.Worldstates.reserve(22);
|
||||
packet.Worldstates.emplace_back(EY_HORDE_BASE, _ownedPointsCount[TEAM_HORDE]);
|
||||
packet.Worldstates.emplace_back(EY_ALLIANCE_BASE, _ownedPointsCount[TEAM_ALLIANCE]);
|
||||
packet.Worldstates.emplace_back(DRAENEI_RUINS_HORDE_CONTROL, _capturePointInfo[POINT_DRAENEI_RUINS].IsUnderControl(TEAM_HORDE));
|
||||
packet.Worldstates.emplace_back(DRAENEI_RUINS_ALLIANCE_CONTROL, _capturePointInfo[POINT_DRAENEI_RUINS].IsUnderControl(TEAM_ALLIANCE));
|
||||
packet.Worldstates.emplace_back(DRAENEI_RUINS_UNCONTROL, _capturePointInfo[POINT_DRAENEI_RUINS].IsUncontrolled());
|
||||
packet.Worldstates.emplace_back(MAGE_TOWER_ALLIANCE_CONTROL, _capturePointInfo[POINT_MAGE_TOWER].IsUnderControl(TEAM_HORDE));
|
||||
packet.Worldstates.emplace_back(MAGE_TOWER_HORDE_CONTROL, _capturePointInfo[POINT_MAGE_TOWER].IsUnderControl(TEAM_ALLIANCE));
|
||||
packet.Worldstates.emplace_back(MAGE_TOWER_UNCONTROL, _capturePointInfo[POINT_MAGE_TOWER].IsUncontrolled());
|
||||
packet.Worldstates.emplace_back(FEL_REAVER_HORDE_CONTROL, _capturePointInfo[POINT_FEL_REAVER].IsUnderControl(TEAM_HORDE));
|
||||
packet.Worldstates.emplace_back(FEL_REAVER_ALLIANCE_CONTROL, _capturePointInfo[POINT_FEL_REAVER].IsUnderControl(TEAM_ALLIANCE));
|
||||
packet.Worldstates.emplace_back(FEL_REAVER_UNCONTROL, _capturePointInfo[POINT_FEL_REAVER].IsUncontrolled());
|
||||
packet.Worldstates.emplace_back(BLOOD_ELF_HORDE_CONTROL, _capturePointInfo[POINT_BLOOD_ELF].IsUnderControl(TEAM_HORDE));
|
||||
packet.Worldstates.emplace_back(BLOOD_ELF_ALLIANCE_CONTROL, _capturePointInfo[POINT_BLOOD_ELF].IsUnderControl(TEAM_ALLIANCE));
|
||||
packet.Worldstates.emplace_back(BLOOD_ELF_UNCONTROL, _capturePointInfo[POINT_BLOOD_ELF].IsUncontrolled());
|
||||
packet.Worldstates.emplace_back(NETHERSTORM_FLAG, _flagState == BG_EY_FLAG_STATE_ON_BASE);
|
||||
packet.Worldstates.emplace_back(NETHERSTORM_FLAG_STATE_HORDE, 1);
|
||||
packet.Worldstates.emplace_back(NETHERSTORM_FLAG_STATE_ALLIANCE, 1);
|
||||
packet.Worldstates.emplace_back(EY_HORDE_RESOURCES, GetTeamScore(TEAM_HORDE));
|
||||
packet.Worldstates.emplace_back(EY_ALLIANCE_RESOURCES, GetTeamScore(TEAM_ALLIANCE));
|
||||
packet.Worldstates.emplace_back(PROGRESS_BAR_SHOW, 0);
|
||||
packet.Worldstates.emplace_back(PROGRESS_BAR_PERCENT_GREY, 0);
|
||||
packet.Worldstates.emplace_back(PROGRESS_BAR_STATUS, 0);
|
||||
}
|
||||
|
||||
GraveyardStruct const* BattlegroundEY::GetClosestGraveyard(Player* player)
|
||||
@@ -608,7 +610,7 @@ GraveyardStruct const* BattlegroundEY::GetClosestGraveyard(Player* player)
|
||||
for (uint8 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
if (_capturePointInfo[i].IsUnderControl(player->GetTeamId()))
|
||||
{
|
||||
entry = sGraveyard->GetGraveyard(m_CapturingPointTypes[i].GraveYardId);
|
||||
entry = sGraveyard->GetGraveyard(m_CapturingPointTypes[i].GraveyardId);
|
||||
dist = (entry->x - pX) * (entry->x - pX) + (entry->y - pY) * (entry->y - pY) + (entry->z - pZ) * (entry->z - pZ);
|
||||
if (dist < minDist)
|
||||
{
|
||||
|
||||
@@ -305,11 +305,11 @@ struct BattlegroundEYLosingPointStruct
|
||||
|
||||
struct BattlegroundEYCapturingPointStruct
|
||||
{
|
||||
BattlegroundEYCapturingPointStruct(uint32 _DespawnNeutralObjectType, uint32 _SpawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _SpawnObjectTypeHorde, uint32 _MessageIdHorde, uint32 _GraveYardId)
|
||||
BattlegroundEYCapturingPointStruct(uint32 _DespawnNeutralObjectType, uint32 _SpawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _SpawnObjectTypeHorde, uint32 _MessageIdHorde, uint32 _GraveyardId)
|
||||
: DespawnNeutralObjectType(_DespawnNeutralObjectType),
|
||||
SpawnObjectTypeAlliance(_SpawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance),
|
||||
SpawnObjectTypeHorde(_SpawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde),
|
||||
GraveYardId(_GraveYardId)
|
||||
GraveyardId(_GraveyardId)
|
||||
{}
|
||||
|
||||
uint32 DespawnNeutralObjectType;
|
||||
@@ -317,7 +317,7 @@ struct BattlegroundEYCapturingPointStruct
|
||||
uint32 MessageIdAlliance;
|
||||
uint32 SpawnObjectTypeHorde;
|
||||
uint32 MessageIdHorde;
|
||||
uint32 GraveYardId;
|
||||
uint32 GraveyardId;
|
||||
};
|
||||
|
||||
const uint32 BG_EY_TickPoints[EY_POINTS_MAX] = {1, 2, 5, 10};
|
||||
@@ -421,7 +421,7 @@ public:
|
||||
void Init() override;
|
||||
void EndBattleground(TeamId winnerTeamId) override;
|
||||
bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
|
||||
void FillInitialWorldStates(WorldPacket& data) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
void SetDroppedFlagGUID(ObjectGuid guid, TeamId /*teamId*/ = TEAM_NEUTRAL) override { _droppedFlagGUID = guid; }
|
||||
ObjectGuid GetDroppedFlagGUID() const { return _droppedFlagGUID; }
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "Transport.h"
|
||||
#include "Vehicle.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
void BattlegroundICScore::BuildObjectivesBlock(WorldPacket& data)
|
||||
{
|
||||
@@ -381,21 +382,24 @@ bool BattlegroundIC::UpdatePlayerScore(Player* player, uint32 type, uint32 value
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundIC::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundIC::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(BG_IC_ALLIANCE_RENFORT_SET) << uint32(1);
|
||||
data << uint32(BG_IC_HORDE_RENFORT_SET) << uint32(1);
|
||||
data << uint32(BG_IC_ALLIANCE_RENFORT) << uint32(factionReinforcements[TEAM_ALLIANCE]);
|
||||
data << uint32(BG_IC_HORDE_RENFORT) << uint32(factionReinforcements[TEAM_HORDE]);
|
||||
packet.Worldstates.reserve(4+MAX_FORTRESS_GATES_SPAWNS+MAX_NODE_TYPES+1);
|
||||
packet.Worldstates.emplace_back(BG_IC_ALLIANCE_RENFORT_SET, 1);
|
||||
packet.Worldstates.emplace_back(BG_IC_HORDE_RENFORT_SET, 1);
|
||||
packet.Worldstates.emplace_back(BG_IC_ALLIANCE_RENFORT, factionReinforcements[TEAM_ALLIANCE]);
|
||||
packet.Worldstates.emplace_back(BG_IC_HORDE_RENFORT, factionReinforcements[TEAM_HORDE]);
|
||||
|
||||
for (uint8 i = 0; i < MAX_FORTRESS_GATES_SPAWNS; ++i)
|
||||
{
|
||||
uint32 uws = GetWorldStateFromGateEntry(BG_IC_ObjSpawnlocs[i].entry, (GateStatus[GetGateIDFromEntry(BG_IC_ObjSpawnlocs[i].entry)] == BG_IC_GATE_DESTROYED));
|
||||
data << uint32(uws) << uint32(1);
|
||||
packet.Worldstates.emplace_back(uws, 1);
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < MAX_NODE_TYPES; ++i)
|
||||
data << uint32(nodePoint[i].worldStates[nodePoint[i].nodeState]) << uint32(1);
|
||||
packet.Worldstates.emplace_back(nodePoint[i].worldStates[nodePoint[i].nodeState], 1);
|
||||
|
||||
packet.Worldstates.emplace_back(BG_IC_HORDE_RENFORT_SET, 1);
|
||||
}
|
||||
|
||||
bool BattlegroundIC::SetupBattleground()
|
||||
|
||||
@@ -974,7 +974,7 @@ public:
|
||||
/* Scorekeeping */
|
||||
bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
|
||||
|
||||
void FillInitialWorldStates(WorldPacket& data) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
|
||||
void HandlePlayerResurrect(Player* player) override;
|
||||
|
||||
|
||||
@@ -64,10 +64,10 @@ void BattlegroundNA::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundNA::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundNA::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(0xa11) << uint32(1); // 9
|
||||
Arena::FillInitialWorldStates(data);
|
||||
packet.Worldstates.emplace_back(0xa11, 1); // BATTLEGROUND_NAGRAND_ARENA_SHOW
|
||||
Arena::FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
bool BattlegroundNA::SetupBattleground()
|
||||
|
||||
@@ -54,7 +54,8 @@ public:
|
||||
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger) override;
|
||||
bool SetupBattleground() override;
|
||||
void FillInitialWorldStates(WorldPacket& d) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
|
||||
bool HandlePlayerUnderMap(Player* player) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -91,10 +91,10 @@ void BattlegroundRL::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundRL::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundRL::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(0xbba) << uint32(1); // 9
|
||||
Arena::FillInitialWorldStates(data);
|
||||
packet.Worldstates.emplace_back(0xbba, 1); // BATTELGROUND_RUINS_OF_LORDAERNON_SHOW
|
||||
Arena::FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
bool BattlegroundRL::SetupBattleground()
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
BattlegroundRL();
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
void FillInitialWorldStates(WorldPacket& d) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
void StartingEventCloseDoors() override;
|
||||
void StartingEventOpenDoors() override;
|
||||
|
||||
|
||||
@@ -204,10 +204,10 @@ void BattlegroundRV::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundRV::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundRV::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(BG_RV_WORLD_STATE) << uint32(1);
|
||||
Arena::FillInitialWorldStates(data);
|
||||
packet.Worldstates.emplace_back(BG_RV_WORLD_STATE, 1);
|
||||
Arena::FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
void BattlegroundRV::Init()
|
||||
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
/* inherited from BattlegroundClass */
|
||||
void StartingEventOpenDoors() override;
|
||||
void Init() override;
|
||||
void FillInitialWorldStates(WorldPacket& d) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger) override;
|
||||
bool SetupBattleground() override;
|
||||
bool HandlePlayerUnderMap(Player* player) override;
|
||||
|
||||
@@ -467,44 +467,46 @@ void BattlegroundSA::StartingEventOpenDoors()
|
||||
{
|
||||
}
|
||||
|
||||
void BattlegroundSA::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundSA::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
uint32 ally_attacks = uint32(Attackers == TEAM_ALLIANCE ? 1 : 0);
|
||||
uint32 horde_attacks = uint32(Attackers == TEAM_HORDE ? 1 : 0);
|
||||
bool const ally_attacks = Attackers == TEAM_ALLIANCE;
|
||||
bool const horde_attacks = Attackers == TEAM_HORDE;
|
||||
|
||||
data << uint32(BG_SA_ANCIENT_GATEWS) << uint32(GateStatus[BG_SA_ANCIENT_GATE]);
|
||||
data << uint32(BG_SA_YELLOW_GATEWS) << uint32(GateStatus[BG_SA_YELLOW_GATE]);
|
||||
data << uint32(BG_SA_GREEN_GATEWS) << uint32(GateStatus[BG_SA_GREEN_GATE]);
|
||||
data << uint32(BG_SA_BLUE_GATEWS) << uint32(GateStatus[BG_SA_BLUE_GATE]);
|
||||
data << uint32(BG_SA_RED_GATEWS) << uint32(GateStatus[BG_SA_RED_GATE]);
|
||||
data << uint32(BG_SA_PURPLE_GATEWS) << uint32(GateStatus[BG_SA_PURPLE_GATE]);
|
||||
packet.Worldstates.reserve(25);
|
||||
packet.Worldstates.emplace_back(BG_SA_ANCIENT_GATEWS, GateStatus[BG_SA_ANCIENT_GATE]);
|
||||
packet.Worldstates.emplace_back(BG_SA_YELLOW_GATEWS, GateStatus[BG_SA_YELLOW_GATE]);
|
||||
packet.Worldstates.emplace_back(BG_SA_GREEN_GATEWS, GateStatus[BG_SA_GREEN_GATE]);
|
||||
packet.Worldstates.emplace_back(BG_SA_BLUE_GATEWS, GateStatus[BG_SA_BLUE_GATE]);
|
||||
packet.Worldstates.emplace_back(BG_SA_RED_GATEWS, GateStatus[BG_SA_RED_GATE]);
|
||||
packet.Worldstates.emplace_back(BG_SA_PURPLE_GATEWS, GateStatus[BG_SA_PURPLE_GATE]);
|
||||
|
||||
data << uint32(BG_SA_BONUS_TIMER) << uint32(0);
|
||||
packet.Worldstates.emplace_back(BG_SA_BONUS_TIMER, 0);
|
||||
|
||||
data << uint32(BG_SA_HORDE_ATTACKS) << horde_attacks;
|
||||
data << uint32(BG_SA_ALLY_ATTACKS) << ally_attacks;
|
||||
packet.Worldstates.emplace_back(BG_SA_HORDE_ATTACKS, horde_attacks);
|
||||
packet.Worldstates.emplace_back(BG_SA_ALLY_ATTACKS, ally_attacks);
|
||||
|
||||
//Time will be sent on first update...
|
||||
data << uint32(BG_SA_ENABLE_TIMER) << ((TimerEnabled) ? uint32(1) : uint32(0));
|
||||
data << uint32(BG_SA_TIMER_MINS) << uint32(0);
|
||||
data << uint32(BG_SA_TIMER_SEC_TENS) << uint32(0);
|
||||
data << uint32(BG_SA_TIMER_SEC_DECS) << uint32(0);
|
||||
packet.Worldstates.emplace_back(BG_SA_ENABLE_TIMER, TimerEnabled ? 1 : 0);
|
||||
|
||||
data << uint32(BG_SA_RIGHT_GY_HORDE) << uint32(GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_HORDE ? 1 : 0);
|
||||
data << uint32(BG_SA_LEFT_GY_HORDE) << uint32(GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_HORDE ? 1 : 0);
|
||||
data << uint32(BG_SA_CENTER_GY_HORDE) << uint32(GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_HORDE ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_SA_TIMER_MINS, 0);
|
||||
packet.Worldstates.emplace_back(BG_SA_TIMER_SEC_TENS, 0);
|
||||
packet.Worldstates.emplace_back(BG_SA_TIMER_SEC_DECS, 0);
|
||||
|
||||
data << uint32(BG_SA_RIGHT_GY_ALLIANCE) << uint32(GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_ALLIANCE ? 1 : 0);
|
||||
data << uint32(BG_SA_LEFT_GY_ALLIANCE) << uint32(GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_ALLIANCE ? 1 : 0);
|
||||
data << uint32(BG_SA_CENTER_GY_ALLIANCE) << uint32(GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_ALLIANCE ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_SA_RIGHT_GY_HORDE, GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_HORDE ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_SA_LEFT_GY_HORDE, GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_HORDE ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_SA_CENTER_GY_HORDE, GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_HORDE ? 1 : 0);
|
||||
|
||||
data << uint32(BG_SA_HORDE_DEFENCE_TOKEN) << ally_attacks;
|
||||
data << uint32(BG_SA_ALLIANCE_DEFENCE_TOKEN) << horde_attacks;
|
||||
packet.Worldstates.emplace_back(BG_SA_RIGHT_GY_ALLIANCE, GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_ALLIANCE ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_SA_LEFT_GY_ALLIANCE, GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_ALLIANCE ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_SA_CENTER_GY_ALLIANCE, GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_ALLIANCE ? 1 : 0);
|
||||
|
||||
data << uint32(BG_SA_LEFT_ATT_TOKEN_HRD) << horde_attacks;
|
||||
data << uint32(BG_SA_RIGHT_ATT_TOKEN_HRD) << horde_attacks;
|
||||
data << uint32(BG_SA_RIGHT_ATT_TOKEN_ALL) << ally_attacks;
|
||||
data << uint32(BG_SA_LEFT_ATT_TOKEN_ALL) << ally_attacks;
|
||||
packet.Worldstates.emplace_back(BG_SA_HORDE_DEFENCE_TOKEN, ally_attacks);
|
||||
packet.Worldstates.emplace_back(BG_SA_ALLIANCE_DEFENCE_TOKEN, horde_attacks);
|
||||
|
||||
packet.Worldstates.emplace_back(BG_SA_LEFT_ATT_TOKEN_HRD, horde_attacks);
|
||||
packet.Worldstates.emplace_back(BG_SA_RIGHT_ATT_TOKEN_HRD, horde_attacks);
|
||||
packet.Worldstates.emplace_back(BG_SA_RIGHT_ATT_TOKEN_ALL, ally_attacks);
|
||||
packet.Worldstates.emplace_back(BG_SA_LEFT_ATT_TOKEN_ALL, ally_attacks);
|
||||
}
|
||||
|
||||
void BattlegroundSA::AddPlayer(Player* player)
|
||||
|
||||
@@ -475,7 +475,7 @@ public:
|
||||
bool SetupBattleground() override;
|
||||
void Init() override;
|
||||
/// Called for generate packet contain worldstate data
|
||||
void FillInitialWorldStates(WorldPacket& data) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
/// Called when a player deal damage to building (door)
|
||||
void EventPlayerDamagedGO(Player* player, GameObject* go, uint32 eventType) override;
|
||||
/// Called when a player kill a unit in bg
|
||||
|
||||
@@ -546,17 +546,18 @@ GraveyardStruct const* BattlegroundWS::GetClosestGraveyard(Player* player)
|
||||
return sGraveyard->GetGraveyard(player->GetTeamId() == TEAM_ALLIANCE ? WS_GRAVEYARD_FLAGROOM_ALLIANCE : WS_GRAVEYARD_FLAGROOM_HORDE);
|
||||
}
|
||||
|
||||
void BattlegroundWS::FillInitialWorldStates(WorldPacket& data)
|
||||
void BattlegroundWS::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
|
||||
{
|
||||
data << uint32(BG_WS_FLAG_CAPTURES_ALLIANCE) << uint32(GetTeamScore(TEAM_ALLIANCE));
|
||||
data << uint32(BG_WS_FLAG_CAPTURES_HORDE) << uint32(GetTeamScore(TEAM_HORDE));
|
||||
data << uint32(BG_WS_FLAG_CAPTURES_MAX) << uint32(BG_WS_MAX_TEAM_SCORE);
|
||||
packet.Worldstates.reserve(7);
|
||||
packet.Worldstates.emplace_back(BG_WS_FLAG_CAPTURES_ALLIANCE, GetTeamScore(TEAM_ALLIANCE));
|
||||
packet.Worldstates.emplace_back(BG_WS_FLAG_CAPTURES_HORDE, GetTeamScore(TEAM_HORDE));
|
||||
packet.Worldstates.emplace_back(BG_WS_FLAG_CAPTURES_MAX, BG_WS_MAX_TEAM_SCORE);
|
||||
|
||||
data << uint32(BG_WS_STATE_TIMER_ACTIVE) << uint32(GetStatus() == STATUS_IN_PROGRESS);
|
||||
data << uint32(BG_WS_STATE_TIMER) << uint32(GetMatchTime());
|
||||
packet.Worldstates.emplace_back(BG_WS_STATE_TIMER_ACTIVE, GetStatus() == STATUS_IN_PROGRESS ? 1 : 0);
|
||||
packet.Worldstates.emplace_back(BG_WS_STATE_TIMER, GetMatchTime());
|
||||
|
||||
data << uint32(BG_WS_FLAG_STATE_HORDE) << uint32(GetFlagState(TEAM_HORDE));
|
||||
data << uint32(BG_WS_FLAG_STATE_ALLIANCE) << uint32(GetFlagState(TEAM_ALLIANCE));
|
||||
packet.Worldstates.emplace_back(BG_WS_FLAG_STATE_HORDE, GetFlagState(TEAM_HORDE));
|
||||
packet.Worldstates.emplace_back(BG_WS_FLAG_STATE_ALLIANCE, GetFlagState(TEAM_ALLIANCE));
|
||||
}
|
||||
|
||||
TeamId BattlegroundWS::GetPrematureWinner()
|
||||
|
||||
@@ -252,7 +252,7 @@ public:
|
||||
bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
|
||||
void SetDroppedFlagGUID(ObjectGuid guid, TeamId teamId) override { _droppedFlagGUID[teamId] = guid; }
|
||||
ObjectGuid GetDroppedFlagGUID(TeamId teamId) const { return _droppedFlagGUID[teamId];}
|
||||
void FillInitialWorldStates(WorldPacket& data) override;
|
||||
void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
|
||||
|
||||
/* Scorekeeping */
|
||||
void AddPoints(TeamId teamId, uint32 points) { m_TeamScores[teamId] += points; }
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "GuildMgr.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "World.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
|
||||
WhoListCacheMgr* WhoListCacheMgr::instance()
|
||||
{
|
||||
@@ -30,7 +31,7 @@ void WhoListCacheMgr::Update()
|
||||
{
|
||||
// clear current list
|
||||
_whoListStorage.clear();
|
||||
_whoListStorage.reserve(sWorld->GetPlayerCount() + 1);
|
||||
_whoListStorage.reserve(sWorldSessionMgr->GetPlayerCount() + 1);
|
||||
|
||||
for (auto const& [guid, player] : ObjectAccessor::GetPlayers())
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
Player* ChatHandler::GetPlayer() const
|
||||
@@ -81,7 +82,7 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac
|
||||
return false;
|
||||
|
||||
// ignore only for non-players for non strong checks (when allow apply command at least to same sec level)
|
||||
if (!AccountMgr::IsPlayerAccount(m_session->GetSecurity()) && !strong && !sWorld->getBoolConfig(CONFIG_GM_LOWER_SECURITY))
|
||||
if (!AccountMgr::IsPlayerAccount(m_session->GetSecurity()) && !strong && sWorld->getBoolConfig(CONFIG_GM_LOWER_SECURITY))
|
||||
return false;
|
||||
|
||||
if (target)
|
||||
@@ -188,7 +189,7 @@ void ChatHandler::SendGlobalSysMessage(const char* str)
|
||||
for (std::string_view line : Acore::Tokenize(str, '\n', true))
|
||||
{
|
||||
BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line);
|
||||
sWorld->SendGlobalMessage(&data);
|
||||
sWorldSessionMgr->SendGlobalMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +199,7 @@ void ChatHandler::SendGlobalGMSysMessage(const char* str)
|
||||
for (std::string_view line : Acore::Tokenize(str, '\n', true))
|
||||
{
|
||||
BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line);
|
||||
sWorld->SendGlobalGMMessage(&data);
|
||||
sWorldSessionMgr->SendGlobalGMMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,8 +515,8 @@ bool ChatHandler::HasSession() const
|
||||
|
||||
void ChatHandler::DoForAllValidSessions(std::function<void(Player*)> exec)
|
||||
{
|
||||
SessionMap::const_iterator itr;
|
||||
for (itr = sWorld->GetAllSessions().begin(); itr != sWorld->GetAllSessions().end(); ++itr)
|
||||
WorldSessionMgr::SessionMap const& sessionMap = sWorldSessionMgr->GetAllSessions();
|
||||
for (WorldSessionMgr::SessionMap::const_iterator itr = sessionMap.begin(); itr != sessionMap.end(); ++itr)
|
||||
if (Player* player = itr->second->GetPlayer())
|
||||
if (player->IsInWorld())
|
||||
exec(player);
|
||||
|
||||
@@ -328,7 +328,7 @@ HostileReference* ThreatContainer::SelectNextVictim(Creature* attacker, HostileR
|
||||
Unit* cvUnit = currentVictim->getTarget();
|
||||
if (!attacker->CanCreatureAttack(cvUnit)) // pussywizard: if currentVictim is not valid => don't compare the threat with it, just take the highest threat valid target
|
||||
currentVictim = nullptr;
|
||||
else if (cvUnit->IsImmunedToDamageOrSchool(attacker->GetMeleeDamageSchoolMask()) || cvUnit->HasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_TAKE_DAMAGE)) // pussywizard: no 10%/30% if currentVictim is immune to damage or has auras breakable by damage
|
||||
else if (cvUnit->IsImmunedToDamageOrSchool(attacker->GetMeleeDamageSchoolMask()) || cvUnit->HasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_TAKE_DAMAGE) || cvUnit->HasUnitState(UNIT_STATE_CONFUSED)) // pussywizard: no 10%/30% if currentVictim is immune to damage or has auras breakable by damage
|
||||
currentVictim = nullptr;
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ HostileReference* ThreatContainer::SelectNextVictim(Creature* attacker, HostileR
|
||||
|
||||
// pussywizard: don't go to threat comparison if this ref is immune to damage or has aura breakable on damage (second choice target)
|
||||
// pussywizard: if this is the last entry on the threat list, then all targets are second choice, set bool to true and loop threat list again, ignoring this section
|
||||
if (!noPriorityTargetFound && (target->IsImmunedToDamageOrSchool(attacker->GetMeleeDamageSchoolMask()) || target->HasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_TAKE_DAMAGE) || target->HasAuraTypeWithCaster(SPELL_AURA_IGNORED, attacker->GetGUID())))
|
||||
if (!noPriorityTargetFound && (target->IsImmunedToDamageOrSchool(attacker->GetMeleeDamageSchoolMask()) || target->HasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_TAKE_DAMAGE) || target->HasUnitState(UNIT_STATE_CONFUSED) || target->HasAuraTypeWithCaster(SPELL_AURA_IGNORED, attacker->GetGUID())))
|
||||
{
|
||||
if (iter != lastRef)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "VMapMgr2.h"
|
||||
#include "World.h"
|
||||
|
||||
std::map<DisableType, std::map<uint32, DisableData>> DisableMgr::m_DisableMap;
|
||||
DisableMgr::DisableMap DisableMgr::m_DisableMap;
|
||||
|
||||
DisableMgr::DisableMgr() {}
|
||||
DisableMgr::~DisableMgr() {}
|
||||
@@ -44,10 +44,8 @@ void DisableMgr::LoadDisables()
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// reload case
|
||||
for (DisableMap::iterator itr = m_DisableMap.begin(); itr != m_DisableMap.end(); ++itr)
|
||||
itr->second.clear();
|
||||
|
||||
m_DisableMap.clear();
|
||||
for (DisableTypeMap& disableTypeMap : m_DisableMap)
|
||||
disableTypeMap.clear();
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT sourceType, entry, flags, params_0, params_1 FROM disables");
|
||||
|
||||
@@ -99,7 +97,7 @@ void DisableMgr::LoadDisables()
|
||||
* @param param0 MapId if DISABLE_TYPE_SPELL used, 0 for all maps.
|
||||
* @param param1 AreaId if DISABLE_TYPE_SPELL used, 0 for all areas.
|
||||
*/
|
||||
void DisableMgr::AddDisable(DisableType type, uint32 entry, uint8 flags, std::string param0, std::string param1)
|
||||
void DisableMgr::AddDisable(DisableType type, uint32 entry, uint8 flags, std::string const& param0, std::string const& param1)
|
||||
{
|
||||
if (type >= MAX_DISABLE_TYPES)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Define.h"
|
||||
#include "Map.h"
|
||||
|
||||
class Unit;
|
||||
|
||||
enum DisableType
|
||||
@@ -68,19 +69,19 @@ public:
|
||||
static DisableMgr* instance();
|
||||
|
||||
void LoadDisables();
|
||||
void AddDisable(DisableType type, uint32 entry, uint8 flags, std::string param0, std::string param1);
|
||||
void AddDisable(DisableType type, uint32 entry, uint8 flags, std::string const& param0, std::string const& param1);
|
||||
bool HandleDisableType(DisableType type, uint32 entry, uint8 flags, std::string const& params_0, std::string const& params_1, DisableData& data);
|
||||
static bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags = 0);
|
||||
void CheckQuestDisables();
|
||||
static bool IsVMAPDisabledFor(uint32 entry, uint8 flags);
|
||||
static bool IsPathfindingEnabled(Map const* map);
|
||||
|
||||
private:
|
||||
// single disables here with optional data
|
||||
typedef std::map<uint32, DisableData> DisableTypeMap;
|
||||
typedef std::unordered_map<uint32, DisableData> DisableTypeMap;
|
||||
// global disable map by source
|
||||
typedef std::map<DisableType, DisableTypeMap> DisableMap;
|
||||
typedef std::array<DisableTypeMap, MAX_DISABLE_TYPES> DisableMap;
|
||||
|
||||
private:
|
||||
static DisableMap m_DisableMap;
|
||||
};
|
||||
|
||||
|
||||
@@ -523,7 +523,7 @@ namespace lfg
|
||||
if (grp && (grp->isBGGroup() || grp->isBFGroup()))
|
||||
return;
|
||||
|
||||
if (!sScriptMgr->CanJoinLfg(player, roles, dungeons, comment))
|
||||
if (!sScriptMgr->OnPlayerCanJoinLfg(player, roles, dungeons, comment))
|
||||
return;
|
||||
|
||||
// pussywizard: can't join LFG/LFR while using LFR
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace lfg
|
||||
{
|
||||
}
|
||||
|
||||
void LFGPlayerScript::OnLevelChanged(Player* player, uint8 /*oldLevel*/)
|
||||
void LFGPlayerScript::OnPlayerLevelChanged(Player* player, uint8 /*oldLevel*/)
|
||||
{
|
||||
if (!sLFGMgr->isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER | LFG_OPTION_ENABLE_SEASONAL_BOSSES))
|
||||
return;
|
||||
@@ -49,7 +49,7 @@ namespace lfg
|
||||
sLFGMgr->InitializeLockedDungeons(player, player->GetGroup());
|
||||
}
|
||||
|
||||
void LFGPlayerScript::OnLogout(Player* player)
|
||||
void LFGPlayerScript::OnPlayerLogout(Player* player)
|
||||
{
|
||||
if (!sLFGMgr->isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER | LFG_OPTION_ENABLE_SEASONAL_BOSSES))
|
||||
return;
|
||||
@@ -69,7 +69,7 @@ namespace lfg
|
||||
sLFGMgr->LfrSearchRemove(player);
|
||||
}
|
||||
|
||||
void LFGPlayerScript::OnLogin(Player* player)
|
||||
void LFGPlayerScript::OnPlayerLogin(Player* player)
|
||||
{
|
||||
if (!sLFGMgr->isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER | LFG_OPTION_ENABLE_SEASONAL_BOSSES))
|
||||
return;
|
||||
@@ -93,14 +93,14 @@ namespace lfg
|
||||
/// @todo - Restore LfgPlayerData and send proper status to player if it was in a group
|
||||
}
|
||||
|
||||
void LFGPlayerScript::OnBindToInstance(Player* player, Difficulty difficulty, uint32 mapId, bool /*permanent*/)
|
||||
void LFGPlayerScript::OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapId, bool /*permanent*/)
|
||||
{
|
||||
MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
|
||||
if (mapEntry->IsDungeon() && difficulty > DUNGEON_DIFFICULTY_NORMAL)
|
||||
sLFGMgr->InitializeLockedDungeons(player, player->GetGroup());
|
||||
}
|
||||
|
||||
void LFGPlayerScript::OnMapChanged(Player* player)
|
||||
void LFGPlayerScript::OnPlayerMapChanged(Player* player)
|
||||
{
|
||||
Map const* map = player->GetMap();
|
||||
|
||||
|
||||
@@ -34,11 +34,11 @@ namespace lfg
|
||||
LFGPlayerScript();
|
||||
|
||||
// Player Hooks
|
||||
void OnLevelChanged(Player* player, uint8 oldLevel) override;
|
||||
void OnLogout(Player* player) override;
|
||||
void OnLogin(Player* player) override;
|
||||
void OnBindToInstance(Player* player, Difficulty difficulty, uint32 mapId, bool permanent) override;
|
||||
void OnMapChanged(Player* player) override;
|
||||
void OnPlayerLevelChanged(Player* player, uint8 oldLevel) override;
|
||||
void OnPlayerLogout(Player* player) override;
|
||||
void OnPlayerLogin(Player* player) override;
|
||||
void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapId, bool permanent) override;
|
||||
void OnPlayerMapChanged(Player* player) override;
|
||||
};
|
||||
|
||||
class LFGGroupScript : public GroupScript
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "WaypointMovementGenerator.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
// however, for some reasons removing it would cause a damn linking issue
|
||||
@@ -1975,7 +1976,8 @@ void Creature::setDeathState(DeathState state, bool despawn)
|
||||
if (state == DeathState::JustDied)
|
||||
{
|
||||
m_corpseRemoveTime = GameTime::GetGameTime().count() + m_corpseDelay;
|
||||
m_respawnTime = GameTime::GetGameTime().count() + m_respawnDelay + m_corpseDelay;
|
||||
uint32 dynamicRespawnDelay = GetMap()->ApplyDynamicModeRespawnScaling(this, m_respawnDelay);
|
||||
m_respawnTime = GameTime::GetGameTime().count() + dynamicRespawnDelay + m_corpseDelay;
|
||||
|
||||
// always save boss respawn time at death to prevent crash cheating
|
||||
if (GetMap()->IsDungeon() || isWorldBoss() || GetCreatureTemplate()->rank >= CREATURE_ELITE_ELITE)
|
||||
@@ -2818,7 +2820,7 @@ void Creature::SendZoneUnderAttackMessage(Player* attacker)
|
||||
{
|
||||
WorldPacket data(SMSG_ZONE_UNDER_ATTACK, 4);
|
||||
data << (uint32)GetAreaId();
|
||||
sWorld->SendGlobalMessage(&data, nullptr, (attacker->GetTeamId() == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE));
|
||||
sWorldSessionMgr->SendGlobalMessage(&data, nullptr, (attacker->GetTeamId() == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3180,7 +3182,8 @@ bool Creature::IsDungeonBoss() const
|
||||
if (GetOwnerGUID().IsPlayer())
|
||||
return false;
|
||||
|
||||
return HasFlagsExtra(CREATURE_FLAG_EXTRA_DUNGEON_BOSS);
|
||||
CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(GetEntry());
|
||||
return cinfo && cinfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_DUNGEON_BOSS);
|
||||
}
|
||||
|
||||
bool Creature::IsImmuneToKnockback() const
|
||||
@@ -3188,7 +3191,8 @@ bool Creature::IsImmuneToKnockback() const
|
||||
if (GetOwnerGUID().IsPlayer())
|
||||
return false;
|
||||
|
||||
return HasFlagsExtra(CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK);
|
||||
CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(GetEntry());
|
||||
return cinfo && cinfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK);
|
||||
}
|
||||
|
||||
bool Creature::HasWeapon(WeaponAttackType type) const
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "MoveSplineInit.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Timer.h"
|
||||
#include "WaypointMgr.h"
|
||||
|
||||
FormationMgr::~FormationMgr()
|
||||
|
||||
@@ -455,14 +455,14 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU
|
||||
|
||||
uint32 moneyRew = 0;
|
||||
Player* player = _session->GetPlayer();
|
||||
if (player && (player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || sScriptMgr->ShouldBeRewardedWithMoneyInsteadOfExp(player)))
|
||||
if (player && (player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || sScriptMgr->OnPlayerShouldBeRewardedWithMoneyInsteadOfExp(player)))
|
||||
{
|
||||
moneyRew = quest->GetRewMoneyMaxLevel();
|
||||
}
|
||||
moneyRew += quest->GetRewOrReqMoney(player ? player->GetLevel() : 0); // reward money (below max lvl)
|
||||
data << moneyRew;
|
||||
uint32 questXp;
|
||||
if (player && !sScriptMgr->ShouldBeRewardedWithMoneyInsteadOfExp(player))
|
||||
if (player && !sScriptMgr->OnPlayerShouldBeRewardedWithMoneyInsteadOfExp(player))
|
||||
{
|
||||
questXp = player->CalculateQuestRewardXP(quest);
|
||||
}
|
||||
@@ -470,7 +470,7 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU
|
||||
{
|
||||
questXp = 0;
|
||||
}
|
||||
sScriptMgr->OnQuestComputeXP(player, quest, questXp);
|
||||
sScriptMgr->OnPlayerQuestComputeXP(player, quest, questXp);
|
||||
data << questXp;
|
||||
}
|
||||
|
||||
@@ -555,7 +555,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const
|
||||
{
|
||||
uint32 moneyRew = 0;
|
||||
Player* player = _session->GetPlayer();
|
||||
if (player && (player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || sScriptMgr->ShouldBeRewardedWithMoneyInsteadOfExp(player)))
|
||||
if (player && (player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || sScriptMgr->OnPlayerShouldBeRewardedWithMoneyInsteadOfExp(player)))
|
||||
{
|
||||
moneyRew = quest->GetRewMoneyMaxLevel();
|
||||
}
|
||||
@@ -707,14 +707,14 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUI
|
||||
|
||||
uint32 moneyRew = 0;
|
||||
Player* player = _session->GetPlayer();
|
||||
if (player && (player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || sScriptMgr->ShouldBeRewardedWithMoneyInsteadOfExp(player)))
|
||||
if (player && (player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || sScriptMgr->OnPlayerShouldBeRewardedWithMoneyInsteadOfExp(player)))
|
||||
{
|
||||
moneyRew = quest->GetRewMoneyMaxLevel();
|
||||
}
|
||||
moneyRew += quest->GetRewOrReqMoney(player ? player->GetLevel() : 0); // reward money (below max lvl)
|
||||
data << moneyRew;
|
||||
uint32 questXp;
|
||||
if (player && !sScriptMgr->ShouldBeRewardedWithMoneyInsteadOfExp(player))
|
||||
if (player && !sScriptMgr->OnPlayerShouldBeRewardedWithMoneyInsteadOfExp(player))
|
||||
{
|
||||
questXp = player->CalculateQuestRewardXP(quest);
|
||||
}
|
||||
@@ -722,7 +722,7 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUI
|
||||
{
|
||||
questXp = 0;
|
||||
}
|
||||
sScriptMgr->OnQuestComputeXP(player, quest, questXp);
|
||||
sScriptMgr->OnPlayerQuestComputeXP(player, quest, questXp);
|
||||
data << questXp;
|
||||
|
||||
// rewarded honor points. Multiply with 10 to satisfy client
|
||||
|
||||
@@ -204,7 +204,7 @@ void TempSummon::InitStats(uint32 duration)
|
||||
Unit* owner = GetSummonerUnit();
|
||||
if (owner)
|
||||
if (Player* player = owner->ToPlayer())
|
||||
sScriptMgr->OnBeforeTempSummonInitStats(player, this, duration);
|
||||
sScriptMgr->OnPlayerBeforeTempSummonInitStats(player, this, duration);
|
||||
|
||||
m_timer = duration;
|
||||
m_lifetime = duration;
|
||||
|
||||
@@ -897,7 +897,8 @@ void GameObject::Update(uint32 diff)
|
||||
return;
|
||||
}
|
||||
|
||||
m_respawnTime = GameTime::GetGameTime().count() + m_respawnDelayTime;
|
||||
uint32 dynamicRespawnDelay = GetMap()->ApplyDynamicModeRespawnScaling(this, m_respawnDelayTime);
|
||||
m_respawnTime = GameTime::GetGameTime().count() + dynamicRespawnDelay;
|
||||
|
||||
// if option not set then object will be saved at grid unload
|
||||
if (GetMap()->IsDungeon())
|
||||
@@ -1758,7 +1759,7 @@ void GameObject::Use(Unit* user)
|
||||
|
||||
LOG_DEBUG("entities.gameobject", "Fishing check (skill: {} zone min skill: {} chance {} roll: {}", skill, zone_skill, chance, roll);
|
||||
|
||||
if (sScriptMgr->OnUpdateFishingSkill(player, skill, zone_skill, chance, roll))
|
||||
if (sScriptMgr->OnPlayerUpdateFishingSkill(player, skill, zone_skill, chance, roll))
|
||||
{
|
||||
player->UpdateFishingSkill();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Timer.h"
|
||||
#include "Util.h"
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
|
||||
@@ -3098,18 +3098,9 @@ void WorldObject::BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& play
|
||||
|
||||
void WorldObject::GetCreaturesWithEntryInRange(std::list<Creature*>& creatureList, float radius, uint32 entry)
|
||||
{
|
||||
CellCoord pair(Acore::ComputeCellCoord(this->GetPositionX(), this->GetPositionY()));
|
||||
Cell cell(pair);
|
||||
cell.SetNoCreate();
|
||||
|
||||
Acore::AllCreaturesOfEntryInRange check(this, entry, radius);
|
||||
Acore::CreatureListSearcher<Acore::AllCreaturesOfEntryInRange> searcher(this, creatureList, check);
|
||||
|
||||
TypeContainerVisitor<Acore::CreatureListSearcher<Acore::AllCreaturesOfEntryInRange>, WorldTypeMapContainer> world_visitor(searcher);
|
||||
cell.Visit(pair, world_visitor, *(this->GetMap()), *this, radius);
|
||||
|
||||
TypeContainerVisitor<Acore::CreatureListSearcher<Acore::AllCreaturesOfEntryInRange>, GridTypeMapContainer> grid_visitor(searcher);
|
||||
cell.Visit(pair, grid_visitor, *(this->GetMap()), *this, radius);
|
||||
Cell::VisitAllObjects(this, searcher, radius);
|
||||
}
|
||||
|
||||
void WorldObject::AddToObjectUpdate()
|
||||
|
||||
@@ -64,6 +64,11 @@ struct Position
|
||||
return !(operator==(a));
|
||||
}
|
||||
|
||||
inline bool operator!=(Position const& a) const
|
||||
{
|
||||
return !(operator==(a));
|
||||
}
|
||||
|
||||
operator G3D::Vector3() const
|
||||
{
|
||||
return { m_positionX, m_positionY, m_positionZ };
|
||||
|
||||
@@ -47,7 +47,7 @@ Pet::Pet(Player* owner, PetType type) : Guardian(nullptr, owner ? owner->GetGUID
|
||||
m_auraRaidUpdateMask(0),
|
||||
m_loading(false),
|
||||
m_petRegenTimer(PET_FOCUS_REGEN_INTERVAL),
|
||||
m_tempspellTarget(nullptr),
|
||||
m_tempspellTarget(),
|
||||
m_tempoldTarget(),
|
||||
m_tempspellIsPositive(false),
|
||||
m_tempspell(0)
|
||||
@@ -237,7 +237,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
|
||||
return false;
|
||||
|
||||
bool forceLoadFromDB = false;
|
||||
sScriptMgr->OnBeforeLoadPetFromDB(owner, petEntry, petnumber, current, forceLoadFromDB);
|
||||
sScriptMgr->OnPlayerBeforeLoadPetFromDB(owner, petEntry, petnumber, current, forceLoadFromDB);
|
||||
|
||||
if (!forceLoadFromDB && (owner->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_PET) && !owner->CanSeeDKPet())) // DK Pet exception
|
||||
return false;
|
||||
@@ -716,9 +716,11 @@ void Pet::Update(uint32 diff)
|
||||
|
||||
if (m_tempspell)
|
||||
{
|
||||
Unit* tempspellTarget = m_tempspellTarget;
|
||||
Unit* tempoldTarget = nullptr;
|
||||
Unit* tempspellTarget = nullptr;
|
||||
if (!m_tempspellTarget.IsEmpty())
|
||||
tempspellTarget = ObjectAccessor::GetUnit(*this, m_tempspellTarget);
|
||||
|
||||
Unit* tempoldTarget = nullptr;
|
||||
if (!m_tempoldTarget.IsEmpty())
|
||||
tempoldTarget = ObjectAccessor::GetUnit(*this, m_tempoldTarget);
|
||||
|
||||
@@ -758,7 +760,7 @@ void Pet::Update(uint32 diff)
|
||||
|
||||
CastSpell(tempspellTarget, tempspell, false);
|
||||
m_tempspell = 0;
|
||||
m_tempspellTarget = nullptr;
|
||||
m_tempspellTarget = ObjectGuid::Empty;
|
||||
|
||||
if (tempspellIsPositive)
|
||||
{
|
||||
@@ -798,7 +800,7 @@ void Pet::Update(uint32 diff)
|
||||
else
|
||||
{
|
||||
m_tempspell = 0;
|
||||
m_tempspellTarget = nullptr;
|
||||
m_tempspellTarget = ObjectGuid::Empty;
|
||||
m_tempoldTarget = ObjectGuid::Empty;
|
||||
m_tempspellIsPositive = false;
|
||||
|
||||
@@ -1031,7 +1033,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
PetType petType = MAX_PET_TYPE;
|
||||
if (owner->IsPlayer())
|
||||
{
|
||||
sScriptMgr->OnBeforeGuardianInitStatsForLevel(owner->ToPlayer(), this, cinfo, petType);
|
||||
sScriptMgr->OnPlayerBeforeGuardianInitStatsForLevel(owner->ToPlayer(), this, cinfo, petType);
|
||||
|
||||
if (IsPet())
|
||||
{
|
||||
@@ -1425,7 +1427,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
|
||||
|
||||
if (owner->IsPlayer())
|
||||
sScriptMgr->OnAfterGuardianInitStatsForLevel(owner->ToPlayer(), this);
|
||||
sScriptMgr->OnPlayerAfterGuardianInitStatsForLevel(owner->ToPlayer(), this);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2433,7 +2435,7 @@ void Pet::CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, ObjectGuid ol
|
||||
if (!spellTarget)
|
||||
return;
|
||||
|
||||
m_tempspellTarget = spellTarget;
|
||||
m_tempspellTarget = spellTarget->GetGUID();
|
||||
m_tempspell = spellid;
|
||||
m_tempspellIsPositive = spellIsPositive;
|
||||
|
||||
@@ -2445,7 +2447,7 @@ void Pet::ClearCastWhenWillAvailable()
|
||||
{
|
||||
m_tempspellIsPositive = false;
|
||||
m_tempspell = 0;
|
||||
m_tempspellTarget = nullptr;
|
||||
m_tempspellTarget = ObjectGuid::Empty;
|
||||
m_tempoldTarget = ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ protected:
|
||||
|
||||
std::unique_ptr<DeclinedName> m_declinedname;
|
||||
|
||||
Unit* m_tempspellTarget;
|
||||
ObjectGuid m_tempspellTarget;
|
||||
ObjectGuid m_tempoldTarget;
|
||||
bool m_tempspellIsPositive;
|
||||
uint32 m_tempspell;
|
||||
|
||||
@@ -167,7 +167,7 @@ void KillRewarder::_RewardXP(Player* player, float rate)
|
||||
AddPct(xp, (*i)->GetAmount());
|
||||
|
||||
// 4.2.3. Give XP to player.
|
||||
sScriptMgr->OnGivePlayerXP(player, xp, _victim, PlayerXPSource::XPSOURCE_KILL);
|
||||
sScriptMgr->OnPlayerGiveXP(player, xp, _victim, PlayerXPSource::XPSOURCE_KILL);
|
||||
player->GiveXP(xp, _victim, _groupRate);
|
||||
if (Pet* pet = player->GetPet())
|
||||
// 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
|
||||
@@ -210,7 +210,7 @@ void KillRewarder::_RewardPlayer(Player* player, bool isDungeon)
|
||||
if (!_isPvP || _isBattleGround)
|
||||
{
|
||||
float xpRate = _group ? _groupRate * float(player->GetLevel()) / _aliveSumLevel : /*Personal rate is 100%.*/ 1.0f; // Group rate depends on the sum of levels.
|
||||
sScriptMgr->OnRewardKillRewarder(player, this, isDungeon, xpRate); // Personal rate is 100%.
|
||||
sScriptMgr->OnPlayerRewardKillRewarder(player, this, isDungeon, xpRate); // Personal rate is 100%.
|
||||
|
||||
if (_xp)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -65,7 +65,7 @@ class SpellCastTargets;
|
||||
class UpdateMask;
|
||||
|
||||
typedef std::deque<Mail*> PlayerMails;
|
||||
typedef void(*bgZoneRef)(Battleground*, WorldPacket&);
|
||||
typedef void(*bgZoneRef)(Battleground*, WorldPackets::WorldState::InitWorldStates&);
|
||||
|
||||
#define PLAYER_MAX_SKILLS 127
|
||||
#define PLAYER_MAX_DAILY_QUESTS 25
|
||||
@@ -2227,7 +2227,7 @@ public:
|
||||
void SetEquipmentSet(uint32 index, EquipmentSet eqset);
|
||||
void DeleteEquipmentSet(uint64 setGuid);
|
||||
|
||||
void SendInitWorldStates(uint32 zone, uint32 area);
|
||||
void SendInitWorldStates(uint32 zoneId, uint32 areaId);
|
||||
void SendUpdateWorldState(uint32 variable, uint32 value) const;
|
||||
void SendDirectMessage(WorldPacket const* data) const;
|
||||
void SendBGWeekendWorldStates();
|
||||
|
||||
@@ -399,7 +399,7 @@ void Player::UpdateFFAPvPFlag(time_t currTime)
|
||||
if (HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
|
||||
{
|
||||
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
|
||||
sScriptMgr->OnFfaPvpStateUpdate(this, false);
|
||||
sScriptMgr->OnPlayerFfaPvpStateUpdate(this, false);
|
||||
}
|
||||
for (ControlSet::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
|
||||
(*itr)->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
|
||||
|
||||
@@ -602,7 +602,7 @@ void Player::CompleteQuest(uint32 quest_id)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sScriptMgr->OnBeforePlayerQuestComplete(this, quest_id))
|
||||
if (!sScriptMgr->OnPlayerBeforeQuestComplete(this, quest_id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -699,7 +699,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
Item* item = StoreNewItem(dest, itemId, true);
|
||||
SendNewItem(item, quest->RewardChoiceItemCount[reward], true, false, false, false);
|
||||
|
||||
sScriptMgr->OnQuestRewardItem(this, item, quest->RewardChoiceItemCount[reward]);
|
||||
sScriptMgr->OnPlayerQuestRewardItem(this, item, quest->RewardChoiceItemCount[reward]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -720,7 +720,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
Item* item = StoreNewItem(dest, itemId, true);
|
||||
SendNewItem(item, quest->RewardItemIdCount[i], true, false, false, false);
|
||||
|
||||
sScriptMgr->OnQuestRewardItem(this, item, quest->RewardItemIdCount[i]);
|
||||
sScriptMgr->OnPlayerQuestRewardItem(this, item, quest->RewardItemIdCount[i]);
|
||||
}
|
||||
else
|
||||
problematicItems.emplace_back(itemId, quest->RewardItemIdCount[i]);
|
||||
@@ -745,15 +745,15 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
// Not give XP in case already completed once repeatable quest
|
||||
uint32 XP = rewarded ? 0 : CalculateQuestRewardXP(quest);
|
||||
|
||||
sScriptMgr->OnQuestComputeXP(this, quest, XP);
|
||||
sScriptMgr->OnPlayerQuestComputeXP(this, quest, XP);
|
||||
int32 moneyRew = 0;
|
||||
if (GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || sScriptMgr->ShouldBeRewardedWithMoneyInsteadOfExp(this))
|
||||
if (GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || sScriptMgr->OnPlayerShouldBeRewardedWithMoneyInsteadOfExp(this))
|
||||
{
|
||||
moneyRew = quest->GetRewMoneyMaxLevel();
|
||||
}
|
||||
else
|
||||
{
|
||||
sScriptMgr->OnGivePlayerXP(this, XP, nullptr, isLFGReward ? PlayerXPSource::XPSOURCE_QUEST_DF : PlayerXPSource::XPSOURCE_QUEST);
|
||||
sScriptMgr->OnPlayerGiveXP(this, XP, nullptr, isLFGReward ? PlayerXPSource::XPSOURCE_QUEST_DF : PlayerXPSource::XPSOURCE_QUEST);
|
||||
GiveXP(XP, nullptr, 1.0f, isLFGReward);
|
||||
}
|
||||
|
||||
@@ -1953,7 +1953,7 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid)
|
||||
if (q_status.Status == QUEST_STATUS_INCOMPLETE && (!GetGroup() || !GetGroup()->isRaidGroup() || qInfo->IsAllowedInRaid(GetMap()->GetDifficulty()) ||
|
||||
(qInfo->IsPVPQuest() && (GetGroup()->isBFGroup() || GetGroup()->isBGGroup()))))
|
||||
{
|
||||
if (!sScriptMgr->PassedQuestKilledMonsterCredit(this, qInfo, entry, real_entry, guid))
|
||||
if (!sScriptMgr->OnPlayerPassedQuestKilledMonsterCredit(this, qInfo, entry, real_entry, guid))
|
||||
continue;
|
||||
|
||||
if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL) /*&& !qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_CAST)*/)
|
||||
|
||||
@@ -1811,7 +1811,7 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool
|
||||
ItemTemplate const* pProto = pItem->GetTemplate();
|
||||
if (pProto)
|
||||
{
|
||||
if (!sScriptMgr->CanEquipItem(const_cast<Player*>(this), slot, dest, pItem, swap, not_loading))
|
||||
if (!sScriptMgr->OnPlayerCanEquipItem(const_cast<Player*>(this), slot, dest, pItem, swap, not_loading))
|
||||
return EQUIP_ERR_CANT_DO_RIGHT_NOW;
|
||||
|
||||
// item used
|
||||
@@ -1983,7 +1983,7 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool
|
||||
|
||||
InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const
|
||||
{
|
||||
if (!sScriptMgr->CanUnequipItem(const_cast<Player*>(this), pos, swap))
|
||||
if (!sScriptMgr->OnPlayerCanUnequipItem(const_cast<Player*>(this), pos, swap))
|
||||
return EQUIP_ERR_CANT_DO_RIGHT_NOW;
|
||||
|
||||
// Applied only to equipped items and bank bags
|
||||
@@ -2326,7 +2326,7 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const
|
||||
|
||||
InventoryResult result = EQUIP_ERR_OK;
|
||||
|
||||
if (!sScriptMgr->CanUseItem(const_cast<Player*>(this), proto, result))
|
||||
if (!sScriptMgr->OnPlayerCanUseItem(const_cast<Player*>(this), proto, result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
@@ -2566,7 +2566,7 @@ Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
sScriptMgr->OnStoreNewItem(this, pItem, count);
|
||||
sScriptMgr->OnPlayerStoreNewItem(this, pItem, count);
|
||||
}
|
||||
return pItem;
|
||||
}
|
||||
@@ -2710,7 +2710,7 @@ Item* Player::EquipNewItem(uint16 pos, uint32 item, bool update)
|
||||
if (!_item)
|
||||
return nullptr;
|
||||
|
||||
if (!IsEquipmentPos(pos) || sScriptMgr->CanSaveEquipNewItem(this, _item, pos, update))
|
||||
if (!IsEquipmentPos(pos) || sScriptMgr->OnPlayerCanSaveEquipNewItem(this, _item, pos, update))
|
||||
{
|
||||
// pussywizard: obtaining blue or better items saves to db
|
||||
if (ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item))
|
||||
@@ -2819,7 +2819,7 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
|
||||
pItem2->SetState(ITEM_CHANGED, this);
|
||||
|
||||
ApplyEquipCooldown(pItem2);
|
||||
sScriptMgr->OnEquip(this, pItem2, bag, slot, update);
|
||||
sScriptMgr->OnPlayerEquip(this, pItem2, bag, slot, update);
|
||||
return pItem2;
|
||||
}
|
||||
|
||||
@@ -2827,7 +2827,7 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry());
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot);
|
||||
|
||||
sScriptMgr->OnEquip(this, pItem, bag, slot, update);
|
||||
sScriptMgr->OnPlayerEquip(this, pItem, bag, slot, update);
|
||||
UpdateForQuestWorldObjects();
|
||||
return pItem;
|
||||
}
|
||||
@@ -2851,7 +2851,7 @@ void Player::QuickEquipItem(uint16 pos, Item* pItem)
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry());
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot);
|
||||
|
||||
sScriptMgr->OnEquip(this, pItem, (pos >> 8), slot, true);
|
||||
sScriptMgr->OnPlayerEquip(this, pItem, (pos >> 8), slot, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2869,7 +2869,7 @@ void Player::SetVisibleItemSlot(uint8 slot, Item* pItem)
|
||||
SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0);
|
||||
}
|
||||
|
||||
sScriptMgr->OnAfterPlayerSetVisibleItemSlot(this, slot, pItem);
|
||||
sScriptMgr->OnPlayerAfterSetVisibleItemSlot(this, slot, pItem);
|
||||
}
|
||||
|
||||
void Player::VisualizeItem(uint8 slot, Item* pItem)
|
||||
@@ -2990,7 +2990,7 @@ void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
|
||||
it->DestroyForPlayer(this);
|
||||
}
|
||||
|
||||
sScriptMgr->OnAfterPlayerMoveItemFromInventory(this, it, bag, slot, update);
|
||||
sScriptMgr->OnPlayerAfterMoveItemFromInventory(this, it, bag, slot, update);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4326,7 +4326,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
|
||||
if (pEnchant->requiredSkill > 0 && pEnchant->requiredSkillValue > GetSkillValue(pEnchant->requiredSkill))
|
||||
return;
|
||||
|
||||
if (!sScriptMgr->CanApplyEnchantment(this, item, slot, apply, apply_dur, ignore_condition))
|
||||
if (!sScriptMgr->OnPlayerCanApplyEnchantment(this, item, slot, apply, apply_dur, ignore_condition))
|
||||
return;
|
||||
|
||||
// If we're dealing with a gem inside a prismatic socket we need to check the prismatic socket requirements
|
||||
@@ -4433,7 +4433,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
|
||||
}
|
||||
}
|
||||
|
||||
sScriptMgr->OnApplyEnchantmentItemModsBefore(this, item, slot, apply, enchant_spell_id, enchant_amount);
|
||||
sScriptMgr->OnPlayerApplyEnchantmentItemModsBefore(this, item, slot, apply, enchant_spell_id, enchant_amount);
|
||||
|
||||
LOG_DEBUG("entities.player.items", "Adding {} to stat nb {}", enchant_amount, enchant_spell_id);
|
||||
switch (enchant_spell_id)
|
||||
@@ -5876,7 +5876,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
|
||||
else if (IsEquipmentPos(INVENTORY_SLOT_BAG_0, slot))
|
||||
{
|
||||
uint16 dest;
|
||||
if (sScriptMgr->CheckItemInSlotAtLoadInventory(this, item, slot, err, dest))
|
||||
if (sScriptMgr->OnPlayerCheckItemInSlotAtLoadInventory(this, item, slot, err, dest))
|
||||
err = CanEquipItem(slot, dest, item, false, false);
|
||||
if (err == EQUIP_ERR_OK)
|
||||
QuickEquipItem(dest, item);
|
||||
@@ -6826,7 +6826,7 @@ bool Player::Satisfy(DungeonProgressionRequirements const* ar, uint32 target_map
|
||||
|| missingPlayerItems.size() || missingPlayerQuests.size() || missingPlayerAchievements.size()
|
||||
|| missingLeaderItems.size() || missingLeaderQuests.size() || missingLeaderAchievements.size())
|
||||
{
|
||||
if (!sScriptMgr->NotAvoidSatisfy(partyLeader, ar, target_map, report))
|
||||
if (!sScriptMgr->OnPlayerNotAvoidSatisfy(partyLeader, ar, target_map, report))
|
||||
return true;
|
||||
|
||||
if (report)
|
||||
|
||||
@@ -55,7 +55,7 @@ void Player::Update(uint32 p_time)
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
sScriptMgr->OnBeforePlayerUpdate(this, p_time);
|
||||
sScriptMgr->OnPlayerBeforeUpdate(this, p_time);
|
||||
|
||||
// undelivered mail
|
||||
if (m_nextMailDelivereTime && m_nextMailDelivereTime <= GameTime::GetGameTime().count())
|
||||
@@ -424,7 +424,7 @@ void Player::Update(uint32 p_time)
|
||||
m_delayed_unit_relocation_timer = 0;
|
||||
RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED);
|
||||
}
|
||||
sScriptMgr->OnAfterPlayerUpdate(this, p_time);
|
||||
sScriptMgr->OnPlayerAfterUpdate(this, p_time);
|
||||
}
|
||||
|
||||
void Player::UpdateMirrorTimers()
|
||||
@@ -551,17 +551,16 @@ void Player::UpdateLocalChannels(uint32 newZone)
|
||||
// names are not changing
|
||||
|
||||
char new_channel_name_buf[100];
|
||||
char const* currentNameExt;
|
||||
std::string currentNameExt;
|
||||
|
||||
if (channel->flags & CHANNEL_DBC_FLAG_CITY_ONLY)
|
||||
currentNameExt = sObjectMgr->GetAcoreStringForDBCLocale(
|
||||
LANG_CHANNEL_CITY).c_str();
|
||||
currentNameExt = sObjectMgr->GetAcoreStringForDBCLocale(LANG_CHANNEL_CITY);
|
||||
else
|
||||
currentNameExt = current_zone_name.c_str();
|
||||
currentNameExt = current_zone_name;
|
||||
|
||||
snprintf(new_channel_name_buf, 100,
|
||||
channel->pattern[m_session->GetSessionDbcLocale()],
|
||||
currentNameExt);
|
||||
currentNameExt.c_str());
|
||||
|
||||
joinChannel = cMgr->GetJoinChannel(new_channel_name_buf,
|
||||
channel->ChannelID);
|
||||
@@ -710,7 +709,7 @@ void Player::UpdateAllRatings()
|
||||
// skill+step, checking for max value
|
||||
bool Player::UpdateSkill(uint32 skill_id, uint32 step)
|
||||
{
|
||||
if (!skill_id)
|
||||
if (!skill_id || !sScriptMgr->OnPlayerCanUpdateSkill(this, skill_id))
|
||||
return false;
|
||||
|
||||
SkillStatusMap::iterator itr = mSkillStatus.find(skill_id);
|
||||
@@ -722,6 +721,8 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step)
|
||||
uint32 value = SKILL_VALUE(data);
|
||||
uint32 max = SKILL_MAX(data);
|
||||
|
||||
sScriptMgr->OnPlayerBeforeUpdateSkill(this, skill_id, value, max, step);
|
||||
|
||||
if ((!max) || (!value) || (value >= max))
|
||||
return false;
|
||||
|
||||
@@ -738,6 +739,8 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step)
|
||||
UpdateSkillEnchantments(skill_id, value, new_value);
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL,
|
||||
skill_id);
|
||||
|
||||
sScriptMgr->OnPlayerUpdateSkill(this, skill_id, value, max, step, new_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -766,7 +769,7 @@ bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue,
|
||||
|
||||
uint32 gathering_skill_gain =
|
||||
sWorld->getIntConfig(CONFIG_SKILL_GAIN_GATHERING);
|
||||
sScriptMgr->OnUpdateGatheringSkill(this, SkillId, SkillValue, RedLevel + 100, RedLevel + 50, RedLevel + 25, gathering_skill_gain);
|
||||
sScriptMgr->OnPlayerUpdateGatheringSkill(this, SkillId, SkillValue, RedLevel + 100, RedLevel + 50, RedLevel + 25, gathering_skill_gain);
|
||||
|
||||
// For skinning and Mining chance decrease with level. 1-74 - no decrease,
|
||||
// 75-149 - 2 times, 225-299 - 8 times
|
||||
@@ -844,7 +847,7 @@ bool Player::UpdateCraftSkill(uint32 spellid)
|
||||
|
||||
uint32 craft_skill_gain =
|
||||
sWorld->getIntConfig(CONFIG_SKILL_GAIN_CRAFTING);
|
||||
sScriptMgr->OnUpdateCraftingSkill(this, _spell_idx->second, SkillValue, craft_skill_gain);
|
||||
sScriptMgr->OnPlayerUpdateCraftingSkill(this, _spell_idx->second, SkillValue, craft_skill_gain);
|
||||
|
||||
return UpdateSkillPro(
|
||||
_spell_idx->second->SkillLine,
|
||||
@@ -913,7 +916,7 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step)
|
||||
LOG_DEBUG("entities.player.skills",
|
||||
"UpdateSkillPro(SkillId {}, Chance {:3.1f}%)", SkillId,
|
||||
Chance / 10.0f);
|
||||
if (!SkillId)
|
||||
if (!SkillId || !sScriptMgr->OnPlayerCanUpdateSkill(this, SkillId))
|
||||
return false;
|
||||
|
||||
if (Chance <= 0) // speedup in 0 chance case
|
||||
@@ -931,8 +934,10 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step)
|
||||
uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos);
|
||||
|
||||
uint32 data = GetUInt32Value(valueIndex);
|
||||
uint16 SkillValue = SKILL_VALUE(data);
|
||||
uint16 MaxValue = SKILL_MAX(data);
|
||||
uint32 SkillValue = SKILL_VALUE(data);
|
||||
uint32 MaxValue = SKILL_MAX(data);
|
||||
|
||||
sScriptMgr->OnPlayerBeforeUpdateSkill(this, SkillId, SkillValue, MaxValue, step);
|
||||
|
||||
if (!MaxValue || !SkillValue || SkillValue >= MaxValue)
|
||||
return false;
|
||||
@@ -964,6 +969,8 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step)
|
||||
LOG_DEBUG("entities.player.skills",
|
||||
"Player::UpdateSkillPro Chance={:3.1f}% taken",
|
||||
Chance / 10.0f);
|
||||
|
||||
sScriptMgr->OnPlayerUpdateSkill(this, SkillId, SkillValue, MaxValue, step, new_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1246,9 +1253,7 @@ void Player::UpdateArea(uint32 newArea)
|
||||
void Player::UpdateZone(uint32 newZone, uint32 newArea)
|
||||
{
|
||||
if (!newZone)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_zoneUpdateId != newZone)
|
||||
{
|
||||
@@ -1265,6 +1270,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
|
||||
guild->UpdateMemberData(this, GUILD_MEMBER_DATA_ZONEID, newZone);
|
||||
}
|
||||
|
||||
GetMap()->UpdatePlayerZoneStats(m_zoneUpdateId, newZone);
|
||||
|
||||
// group update
|
||||
if (GetGroup())
|
||||
SetGroupUpdateFlag(GROUP_UPDATE_FULL);
|
||||
@@ -1377,7 +1384,7 @@ void Player::UpdateEquipSpellsAtFormChange()
|
||||
|
||||
ApplyEquipSpell(spellInfo, nullptr, false,
|
||||
true); // remove spells that not fit to form
|
||||
if (!sScriptMgr->CanApplyEquipSpellsItemSet(this, eff))
|
||||
if (!sScriptMgr->OnPlayerCanApplyEquipSpellsItemSet(this, eff))
|
||||
break;
|
||||
ApplyEquipSpell(spellInfo, nullptr, true,
|
||||
true); // add spells that fit form but not active
|
||||
@@ -1455,7 +1462,7 @@ void Player::UpdateFFAPvPState(bool reset /*= true*/)
|
||||
{
|
||||
if (!IsFFAPvP())
|
||||
{
|
||||
sScriptMgr->OnFfaPvpStateUpdate(this, true);
|
||||
sScriptMgr->OnPlayerFfaPvpStateUpdate(this, true);
|
||||
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
|
||||
for (ControlSet::iterator itr = m_Controlled.begin();
|
||||
itr != m_Controlled.end(); ++itr)
|
||||
@@ -1477,7 +1484,7 @@ void Player::UpdateFFAPvPState(bool reset /*= true*/)
|
||||
if (HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
|
||||
{
|
||||
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
|
||||
sScriptMgr->OnFfaPvpStateUpdate(this, false);
|
||||
sScriptMgr->OnPlayerFfaPvpStateUpdate(this, false);
|
||||
}
|
||||
for (ControlSet::iterator itr = m_Controlled.begin();
|
||||
itr != m_Controlled.end(); ++itr)
|
||||
@@ -2379,7 +2386,15 @@ void Player::ProcessSpellQueue()
|
||||
if (CanExecutePendingSpellCastRequest(spellInfo))
|
||||
{
|
||||
ExecuteOrCancelSpellCastRequest(&request);
|
||||
SpellQueue.pop_front(); // Remove from the queue
|
||||
|
||||
// ExecuteOrCancelSpellCastRequest() can lead to clearing the SpellQueue.
|
||||
// Example scenario:
|
||||
// Handling a spell → Dealing damage to yourself (e.g., spell_pri_vampiric_touch) →
|
||||
// Killing yourself → Player::setDeathState() → SpellQueue.clear().
|
||||
// Calling std::deque::pop_front() on an empty deque results in undefined behavior,
|
||||
// so an additional check is added.
|
||||
if (!SpellQueue.empty())
|
||||
SpellQueue.pop_front();
|
||||
}
|
||||
else // If the first spell can't execute, stop processing
|
||||
break;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define TRANSPORTS_H
|
||||
|
||||
#include "GameObject.h"
|
||||
#include "Timer.h"
|
||||
#include "TransportMgr.h"
|
||||
#include "VehicleDefines.h"
|
||||
#include "ZoneScript.h"
|
||||
|
||||
@@ -302,7 +302,7 @@ void Player::UpdateMaxHealth()
|
||||
value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
|
||||
value *= GetModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
sScriptMgr->OnAfterUpdateMaxHealth(this, value);
|
||||
sScriptMgr->OnPlayerAfterUpdateMaxHealth(this, value);
|
||||
SetMaxHealth((uint32)value);
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ void Player::UpdateMaxPower(Powers power)
|
||||
value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
|
||||
value *= GetModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
sScriptMgr->OnAfterUpdateMaxPower(this, power, value);
|
||||
sScriptMgr->OnPlayerAfterUpdateMaxPower(this, power, value);
|
||||
SetMaxPower(power, uint32(value));
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
||||
float val2 = 0.0f;
|
||||
float level = float(GetLevel());
|
||||
|
||||
sScriptMgr->OnBeforeUpdateAttackPowerAndDamage(this, level, val2, ranged);
|
||||
sScriptMgr->OnPlayerBeforeUpdateAttackPowerAndDamage(this, level, val2, ranged);
|
||||
|
||||
UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
|
||||
|
||||
@@ -499,7 +499,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
||||
|
||||
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
|
||||
|
||||
sScriptMgr->OnAfterUpdateAttackPowerAndDamage(this, level, base_attPower, attPowerMod, attPowerMultiplier, ranged);
|
||||
sScriptMgr->OnPlayerAfterUpdateAttackPowerAndDamage(this, level, base_attPower, attPowerMod, attPowerMultiplier, ranged);
|
||||
SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
|
||||
SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
|
||||
SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
|
||||
|
||||
@@ -819,7 +819,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
|
||||
victim->GetAI()->DamageTaken(attacker, damage, damagetype, damageSchoolMask);
|
||||
|
||||
if (attacker && attacker->IsAIEnabled)
|
||||
attacker->GetAI()->DamageDealt(victim, damage, damagetype);
|
||||
attacker->GetAI()->DamageDealt(victim, damage, damagetype, damageSchoolMask);
|
||||
}
|
||||
|
||||
// Hook for OnDamage Event
|
||||
@@ -17897,7 +17897,7 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
|
||||
if (Unit* owner = killer->GetOwner())
|
||||
{
|
||||
Unit::ProcDamageAndSpell(owner, victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
|
||||
sScriptMgr->OnCreatureKilledByPet( killer->GetCharmerOrOwnerPlayerOrPlayerItself(), victim->ToCreature());
|
||||
sScriptMgr->OnPlayerCreatureKilledByPet( killer->GetCharmerOrOwnerPlayerOrPlayerItself(), victim->ToCreature());
|
||||
}
|
||||
|
||||
if (killer != victim)
|
||||
@@ -18099,9 +18099,9 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
|
||||
if (Player* killerPlr = killer->ToPlayer())
|
||||
{
|
||||
if (Player* killedPlr = victim->ToPlayer())
|
||||
sScriptMgr->OnPVPKill(killerPlr, killedPlr);
|
||||
sScriptMgr->OnPlayerPVPKill(killerPlr, killedPlr);
|
||||
else if (Creature* killedCre = victim->ToCreature())
|
||||
sScriptMgr->OnCreatureKill(killerPlr, killedCre);
|
||||
sScriptMgr->OnPlayerCreatureKill(killerPlr, killedCre);
|
||||
}
|
||||
else if (Creature* killerCre = killer->ToCreature())
|
||||
{
|
||||
@@ -20566,6 +20566,8 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
|
||||
}
|
||||
}
|
||||
|
||||
GetMap()->LoadGridsInRange(*player, MAX_VISIBILITY_DISTANCE);
|
||||
|
||||
Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance
|
||||
Cell::VisitAllObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
|
||||
relocateNoLarge.SendToSelf();
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "Transport.h"
|
||||
#include "UnitAI.h"
|
||||
#include "World.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
#include "WorldStatePackets.h"
|
||||
#include <time.h>
|
||||
|
||||
@@ -1163,34 +1164,6 @@ uint32 GameEventMgr::StartSystem() // return the next
|
||||
return delay;
|
||||
}
|
||||
|
||||
void GameEventMgr::StartArenaSeason()
|
||||
{
|
||||
uint8 season = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID);
|
||||
|
||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_GAME_EVENT_ARENA_SEASON);
|
||||
stmt->SetData(0, season);
|
||||
PreparedQueryResult result = WorldDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_ERROR("gameevent", "ArenaSeason ({}) must be an existant Arena Season", season);
|
||||
return;
|
||||
}
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
uint16 eventId = fields[0].Get<uint8>();
|
||||
|
||||
if (eventId >= _gameEvent.size())
|
||||
{
|
||||
LOG_ERROR("gameevent", "EventEntry {} for ArenaSeason ({}) does not exists", eventId, season);
|
||||
return;
|
||||
}
|
||||
|
||||
StartEvent(eventId, true);
|
||||
LOG_INFO("server.loading", "Arena Season {} started...", season);
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
uint32 GameEventMgr::Update() // return the next event delay in ms
|
||||
{
|
||||
time_t currenttime = GameTime::GetGameTime().count();
|
||||
@@ -1714,7 +1687,7 @@ void GameEventMgr::UpdateWorldStates(uint16 eventId, bool Activate)
|
||||
WorldPackets::WorldState::UpdateWorldState worldstate;
|
||||
worldstate.VariableID = bl->HolidayWorldStateId;
|
||||
worldstate.Value = Activate ? 1 : 0;
|
||||
sWorld->SendGlobalMessage(worldstate.Write());
|
||||
sWorldSessionMgr->SendGlobalMessage(worldstate.Write());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,11 +115,10 @@ public:
|
||||
bool IsActiveEvent(uint16 eventId) { return (_activeEvents.find(eventId) != _activeEvents.end()); }
|
||||
uint32 StartSystem();
|
||||
void Initialize();
|
||||
void StartArenaSeason();
|
||||
void StartInternalEvent(uint16 eventId);
|
||||
bool StartEvent(uint16 eventId, bool overwrite = false);
|
||||
void StopEvent(uint16 eventId, bool overwrite = false);
|
||||
void HandleQuestComplete(uint32 questId); // called on world event type quest completions
|
||||
void StartInternalEvent(uint16 event_id);
|
||||
bool StartEvent(uint16 event_id, bool overwrite = false);
|
||||
void StopEvent(uint16 event_id, bool overwrite = false);
|
||||
void HandleQuestComplete(uint32 quest_id); // called on world event type quest completions
|
||||
uint32 GetNPCFlag(Creature* cr);
|
||||
// Load the game event npc vendor table from the DB
|
||||
void LoadEventVendors();
|
||||
|
||||
@@ -2341,8 +2341,8 @@ void ObjectMgr::AddCreatureToGrid(ObjectGuid::LowType guid, CreatureData const*
|
||||
{
|
||||
if (mask & 1)
|
||||
{
|
||||
CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY);
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
|
||||
GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY);
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()];
|
||||
cell_guids.creatures.insert(guid);
|
||||
}
|
||||
}
|
||||
@@ -2355,8 +2355,8 @@ void ObjectMgr::RemoveCreatureFromGrid(ObjectGuid::LowType guid, CreatureData co
|
||||
{
|
||||
if (mask & 1)
|
||||
{
|
||||
CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY);
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
|
||||
GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY);
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()];
|
||||
cell_guids.creatures.erase(guid);
|
||||
}
|
||||
}
|
||||
@@ -2454,7 +2454,7 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 mapId, float x, float y, float
|
||||
AddCreatureToGrid(spawnId, &data);
|
||||
|
||||
// Spawn if necessary (loaded grids only)
|
||||
if (!map->Instanceable() && !map->IsRemovalGrid(x, y))
|
||||
if (!map->Instanceable() && !map->IsGridCreated(x, y))
|
||||
{
|
||||
Creature* creature = new Creature();
|
||||
if (!creature->LoadCreatureFromDB(spawnId, map, true, true))
|
||||
@@ -2644,8 +2644,8 @@ void ObjectMgr::AddGameobjectToGrid(ObjectGuid::LowType guid, GameObjectData con
|
||||
{
|
||||
if (mask & 1)
|
||||
{
|
||||
CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY);
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
|
||||
GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY);
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()];
|
||||
cell_guids.gameobjects.insert(guid);
|
||||
}
|
||||
}
|
||||
@@ -2658,8 +2658,8 @@ void ObjectMgr::RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectDat
|
||||
{
|
||||
if (mask & 1)
|
||||
{
|
||||
CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY);
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
|
||||
GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY);
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()];
|
||||
cell_guids.gameobjects.erase(guid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1151,12 +1151,12 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id)
|
||||
CellObjectGuids const& GetGridObjectGuids(uint16 mapid, uint8 spawnMode, uint32 gridId)
|
||||
{
|
||||
MapObjectGuids::const_iterator itr1 = _mapObjectGuidsStore.find(MAKE_PAIR32(mapid, spawnMode));
|
||||
if (itr1 != _mapObjectGuidsStore.end())
|
||||
{
|
||||
CellObjectGuidsMap::const_iterator itr2 = itr1->second.find(cell_id);
|
||||
CellObjectGuidsMap::const_iterator itr2 = itr1->second.find(gridId);
|
||||
if (itr2 != itr1->second.end())
|
||||
return itr2->second;
|
||||
}
|
||||
|
||||
@@ -70,8 +70,6 @@ struct Cell
|
||||
[[nodiscard]] uint32 CellY() const { return data.Part.cell_y; }
|
||||
[[nodiscard]] uint32 GridX() const { return data.Part.grid_x; }
|
||||
[[nodiscard]] uint32 GridY() const { return data.Part.grid_y; }
|
||||
[[nodiscard]] bool NoCreate() const { return data.Part.nocreate; }
|
||||
void SetNoCreate() { data.Part.nocreate = 1; }
|
||||
|
||||
[[nodiscard]] CellCoord GetCellCoord() const
|
||||
{
|
||||
@@ -92,12 +90,10 @@ struct Cell
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned grid_x : 6;
|
||||
unsigned grid_y : 6;
|
||||
unsigned cell_x : 6;
|
||||
unsigned cell_y : 6;
|
||||
unsigned nocreate : 1;
|
||||
unsigned reserved : 7;
|
||||
unsigned grid_x : 8;
|
||||
unsigned grid_y : 8;
|
||||
unsigned cell_x : 8;
|
||||
unsigned cell_y : 8;
|
||||
} Part;
|
||||
uint32 All;
|
||||
} data;
|
||||
@@ -107,13 +103,13 @@ struct Cell
|
||||
|
||||
static CellArea CalculateCellArea(float x, float y, float radius);
|
||||
|
||||
template<class T> static void VisitGridObjects(WorldObject const* obj, T& visitor, float radius, bool dont_load = true);
|
||||
template<class T> static void VisitWorldObjects(WorldObject const* obj, T& visitor, float radius, bool dont_load = true);
|
||||
template<class T> static void VisitAllObjects(WorldObject const* obj, T& visitor, float radius, bool dont_load = true);
|
||||
template<class T> static void VisitGridObjects(WorldObject const* obj, T& visitor, float radius);
|
||||
template<class T> static void VisitWorldObjects(WorldObject const* obj, T& visitor, float radius);
|
||||
template<class T> static void VisitAllObjects(WorldObject const* obj, T& visitor, float radius);
|
||||
|
||||
template<class T> static void VisitGridObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load = true);
|
||||
template<class T> static void VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load = true);
|
||||
template<class T> static void VisitAllObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load = true);
|
||||
template<class T> static void VisitGridObjects(float x, float y, Map* map, T& visitor, float radius);
|
||||
template<class T> static void VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius);
|
||||
template<class T> static void VisitAllObjects(float x, float y, Map* map, T& visitor, float radius);
|
||||
|
||||
private:
|
||||
template<class T, class CONTAINER> void VisitCircle(TypeContainerVisitor<T, CONTAINER>&, Map&, CellCoord const&, CellCoord const&) const;
|
||||
|
||||
@@ -28,8 +28,6 @@ inline Cell::Cell(CellCoord const& p)
|
||||
data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS;
|
||||
data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS;
|
||||
data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS;
|
||||
data.Part.nocreate = 0;
|
||||
data.Part.reserved = 0;
|
||||
}
|
||||
|
||||
inline Cell::Cell(float x, float y)
|
||||
@@ -39,8 +37,6 @@ inline Cell::Cell(float x, float y)
|
||||
data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS;
|
||||
data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS;
|
||||
data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS;
|
||||
data.Part.nocreate = 0;
|
||||
data.Part.reserved = 0;
|
||||
}
|
||||
|
||||
inline CellArea Cell::CalculateCellArea(float x, float y, float radius)
|
||||
@@ -51,8 +47,8 @@ inline CellArea Cell::CalculateCellArea(float x, float y, float radius)
|
||||
return CellArea(center, center);
|
||||
}
|
||||
|
||||
CellCoord centerX = Acore::ComputeCellCoord(x - radius, y - radius).normalize();
|
||||
CellCoord centerY = Acore::ComputeCellCoord(x + radius, y + radius).normalize();
|
||||
CellCoord centerX = Acore::ComputeCellCoord(x + radius, y + radius).normalize();
|
||||
CellCoord centerY = Acore::ComputeCellCoord(x - radius, y - radius).normalize();
|
||||
|
||||
return CellArea(centerX, centerY);
|
||||
}
|
||||
@@ -66,7 +62,8 @@ inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T,
|
||||
}
|
||||
|
||||
template<class T, class CONTAINER>
|
||||
inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, float x_off, float y_off, float radius) const{
|
||||
inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, float x_off, float y_off, float radius) const
|
||||
{
|
||||
if (!standing_cell.IsCoordValid())
|
||||
return;
|
||||
|
||||
@@ -101,23 +98,16 @@ inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T,
|
||||
return;
|
||||
}
|
||||
|
||||
//ALWAYS visit standing cell first!!! Since we deal with small radiuses
|
||||
//it is very essential to call visitor for standing cell firstly...
|
||||
map.Visit(*this, visitor);
|
||||
|
||||
// loop the cell range
|
||||
ASSERT(area.high_bound.x_coord >= area.low_bound.x_coord);
|
||||
ASSERT(area.high_bound.y_coord >= area.low_bound.y_coord);
|
||||
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
|
||||
{
|
||||
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
|
||||
{
|
||||
CellCoord cellCoord(x, y);
|
||||
//lets skip standing cell since we already visited it
|
||||
if (cellCoord != standing_cell)
|
||||
{
|
||||
Cell r_zone(cellCoord);
|
||||
r_zone.data.Part.nocreate = this->data.Part.nocreate;
|
||||
map.Visit(r_zone, visitor);
|
||||
}
|
||||
Cell r_zone(cellCoord);
|
||||
map.Visit(r_zone, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,7 +128,6 @@ inline void Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER>& visitor, Map&
|
||||
{
|
||||
CellCoord cellCoord(x, y);
|
||||
Cell r_zone(cellCoord);
|
||||
r_zone.data.Part.nocreate = this->data.Part.nocreate;
|
||||
map.Visit(r_zone, visitor);
|
||||
}
|
||||
}
|
||||
@@ -162,55 +151,41 @@ inline void Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER>& visitor, Map&
|
||||
//e.g. filling 2 trapezoids after filling central cell strip...
|
||||
CellCoord cellCoord_left(x_start - step, y);
|
||||
Cell r_zone_left(cellCoord_left);
|
||||
r_zone_left.data.Part.nocreate = this->data.Part.nocreate;
|
||||
map.Visit(r_zone_left, visitor);
|
||||
|
||||
//right trapezoid cell visit
|
||||
CellCoord cellCoord_right(x_end + step, y);
|
||||
Cell r_zone_right(cellCoord_right);
|
||||
r_zone_right.data.Part.nocreate = this->data.Part.nocreate;
|
||||
map.Visit(r_zone_right, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Cell::VisitGridObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/)
|
||||
inline void Cell::VisitGridObjects(WorldObject const* center_obj, T& visitor, float radius)
|
||||
{
|
||||
CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
|
||||
Cell cell(p);
|
||||
if (dont_load)
|
||||
{
|
||||
cell.SetNoCreate();
|
||||
}
|
||||
|
||||
TypeContainerVisitor<T, GridTypeMapContainer> gnotifier(visitor);
|
||||
cell.Visit(p, gnotifier, *center_obj->GetMap(), *center_obj, radius);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Cell::VisitWorldObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/)
|
||||
inline void Cell::VisitWorldObjects(WorldObject const* center_obj, T& visitor, float radius)
|
||||
{
|
||||
CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
|
||||
Cell cell(p);
|
||||
if (dont_load)
|
||||
{
|
||||
cell.SetNoCreate();
|
||||
}
|
||||
|
||||
TypeContainerVisitor<T, WorldTypeMapContainer> wnotifier(visitor);
|
||||
cell.Visit(p, wnotifier, *center_obj->GetMap(), *center_obj, radius);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/)
|
||||
inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, float radius)
|
||||
{
|
||||
CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
|
||||
Cell cell(p);
|
||||
if (dont_load)
|
||||
{
|
||||
cell.SetNoCreate();
|
||||
}
|
||||
|
||||
TypeContainerVisitor<T, WorldTypeMapContainer> wnotifier(visitor);
|
||||
cell.Visit(p, wnotifier, *center_obj->GetMap(), *center_obj, radius);
|
||||
@@ -219,42 +194,30 @@ inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, flo
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Cell::VisitGridObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/)
|
||||
inline void Cell::VisitGridObjects(float x, float y, Map* map, T& visitor, float radius)
|
||||
{
|
||||
CellCoord p(Acore::ComputeCellCoord(x, y));
|
||||
Cell cell(p);
|
||||
if (dont_load)
|
||||
{
|
||||
cell.SetNoCreate();
|
||||
}
|
||||
|
||||
TypeContainerVisitor<T, GridTypeMapContainer> gnotifier(visitor);
|
||||
cell.Visit(p, gnotifier, *map, x, y, radius);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Cell::VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/)
|
||||
inline void Cell::VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius)
|
||||
{
|
||||
CellCoord p(Acore::ComputeCellCoord(x, y));
|
||||
Cell cell(p);
|
||||
if (dont_load)
|
||||
{
|
||||
cell.SetNoCreate();
|
||||
}
|
||||
|
||||
TypeContainerVisitor<T, WorldTypeMapContainer> wnotifier(visitor);
|
||||
cell.Visit(p, wnotifier, *map, x, y, radius);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Cell::VisitAllObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/)
|
||||
inline void Cell::VisitAllObjects(float x, float y, Map* map, T& visitor, float radius)
|
||||
{
|
||||
CellCoord p(Acore::ComputeCellCoord(x, y));
|
||||
Cell cell(p);
|
||||
if (dont_load)
|
||||
{
|
||||
cell.SetNoCreate();
|
||||
}
|
||||
|
||||
TypeContainerVisitor<T, WorldTypeMapContainer> wnotifier(visitor);
|
||||
cell.Visit(p, wnotifier, *map, x, y, radius);
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACORE_GRID_H
|
||||
#define ACORE_GRID_H
|
||||
|
||||
/*
|
||||
@class Grid
|
||||
Grid is a logical segment of the game world represented inside TrinIty.
|
||||
Grid is bind at compile time to a particular type of object which
|
||||
we call it the object of interested. There are many types of loader,
|
||||
specially, dynamic loader, static loader, or on-demand loader. There's
|
||||
a subtle difference between dynamic loader and on-demand loader but
|
||||
this is implementation specific to the loader class. From the
|
||||
Grid's perspective, the loader meets its API requirement is suffice.
|
||||
*/
|
||||
|
||||
#include "Define.h"
|
||||
#include "TypeContainer.h"
|
||||
#include "TypeContainerVisitor.h"
|
||||
|
||||
// forward declaration
|
||||
template<class A, class T, class O> class GridLoader;
|
||||
|
||||
template
|
||||
<
|
||||
class ACTIVE_OBJECT,
|
||||
class WORLD_OBJECT_TYPES,
|
||||
class GRID_OBJECT_TYPES
|
||||
>
|
||||
class Grid
|
||||
{
|
||||
// allows the GridLoader to access its internals
|
||||
template<class A, class T, class O> friend class GridLoader;
|
||||
public:
|
||||
/** destructor to clean up its resources. This includes unloading the
|
||||
grid if it has not been unload.
|
||||
*/
|
||||
~Grid() = default;
|
||||
|
||||
/** an object of interested enters the grid
|
||||
*/
|
||||
template<class SPECIFIC_OBJECT> void AddWorldObject(SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
i_objects.template insert<SPECIFIC_OBJECT>(obj);
|
||||
ASSERT(obj->IsInGrid());
|
||||
}
|
||||
|
||||
/** an object of interested exits the grid
|
||||
*/
|
||||
//Actually an unlink is enough, no need to go through the container
|
||||
//template<class SPECIFIC_OBJECT> void RemoveWorldObject(SPECIFIC_OBJECT *obj)
|
||||
//{
|
||||
// ASSERT(obj->GetGridRef().isValid());
|
||||
// i_objects.template remove<SPECIFIC_OBJECT>(obj);
|
||||
// ASSERT(!obj->GetGridRef().isValid());
|
||||
//}
|
||||
|
||||
/** Refreshes/update the grid. This required for remote grids.
|
||||
*/
|
||||
//void RefreshGrid(void) { /* TBI */}
|
||||
|
||||
/** Locks a grid. Any object enters must wait until the grid is unlock.
|
||||
*/
|
||||
//void LockGrid(void) { /* TBI */ }
|
||||
|
||||
/** Unlocks the grid.
|
||||
*/
|
||||
//void UnlockGrid(void) { /* TBI */ }
|
||||
|
||||
// Visit grid objects
|
||||
template<class T>
|
||||
void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES> >& visitor)
|
||||
{
|
||||
visitor.Visit(i_container);
|
||||
}
|
||||
|
||||
// Visit world objects
|
||||
template<class T>
|
||||
void Visit(TypeContainerVisitor<T, TypeMapContainer<WORLD_OBJECT_TYPES> >& visitor)
|
||||
{
|
||||
visitor.Visit(i_objects);
|
||||
}
|
||||
|
||||
/** Inserts a container type object into the grid.
|
||||
*/
|
||||
template<class SPECIFIC_OBJECT> void AddGridObject(SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
i_container.template insert<SPECIFIC_OBJECT>(obj);
|
||||
ASSERT(obj->IsInGrid());
|
||||
}
|
||||
|
||||
/** Removes a containter type object from the grid
|
||||
*/
|
||||
//template<class SPECIFIC_OBJECT> void RemoveGridObject(SPECIFIC_OBJECT *obj)
|
||||
//{
|
||||
// ASSERT(obj->GetGridRef().isValid());
|
||||
// i_container.template remove<SPECIFIC_OBJECT>(obj);
|
||||
// ASSERT(!obj->GetGridRef().isValid());
|
||||
//}
|
||||
|
||||
/*bool NoWorldObjectInGrid() const
|
||||
{
|
||||
return i_objects.GetElements().IsEmpty();
|
||||
}
|
||||
|
||||
bool NoGridObjectInGrid() const
|
||||
{
|
||||
return i_container.GetElements().IsEmpty();
|
||||
}*/
|
||||
private:
|
||||
TypeMapContainer<GRID_OBJECT_TYPES> i_container;
|
||||
TypeMapContainer<WORLD_OBJECT_TYPES> i_objects;
|
||||
//typedef std::set<void*> ActiveGridObjects;
|
||||
//ActiveGridObjects m_activeGridObjects;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACORE_GRID_CELL_H
|
||||
#define ACORE_GRID_CELL_H
|
||||
|
||||
/*
|
||||
@class GridCell
|
||||
Grid is a logical segment of the game world represented inside TrinIty.
|
||||
Grid is bind at compile time to a particular type of object which
|
||||
we call it the object of interested. There are many types of loader,
|
||||
specially, dynamic loader, static loader, or on-demand loader. There's
|
||||
a subtle difference between dynamic loader and on-demand loader but
|
||||
this is implementation specific to the loader class. From the
|
||||
Grid's perspective, the loader meets its API requirement is suffice.
|
||||
*/
|
||||
|
||||
#include "Define.h"
|
||||
#include "TypeContainer.h"
|
||||
#include "TypeContainerVisitor.h"
|
||||
|
||||
template
|
||||
<
|
||||
class WORLD_OBJECT_TYPES,
|
||||
class GRID_OBJECT_TYPES
|
||||
>
|
||||
class GridCell
|
||||
{
|
||||
public:
|
||||
~GridCell() = default;
|
||||
|
||||
template<class SPECIFIC_OBJECT> void AddWorldObject(SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
_worldObjects.template insert<SPECIFIC_OBJECT>(obj);
|
||||
ASSERT(obj->IsInGrid());
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT> void AddGridObject(SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
_gridObjects.template insert<SPECIFIC_OBJECT>(obj);
|
||||
ASSERT(obj->IsInGrid());
|
||||
}
|
||||
|
||||
// Visit grid objects
|
||||
template<class T>
|
||||
void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES> >& visitor)
|
||||
{
|
||||
visitor.Visit(_gridObjects);
|
||||
}
|
||||
|
||||
// Visit world objects
|
||||
template<class T>
|
||||
void Visit(TypeContainerVisitor<T, TypeMapContainer<WORLD_OBJECT_TYPES> >& visitor)
|
||||
{
|
||||
visitor.Visit(_worldObjects);
|
||||
}
|
||||
private:
|
||||
TypeMapContainer<GRID_OBJECT_TYPES> _gridObjects;
|
||||
TypeMapContainer<WORLD_OBJECT_TYPES> _worldObjects;
|
||||
};
|
||||
#endif
|
||||
@@ -20,7 +20,8 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "MapDefines.h"
|
||||
#include "NGrid.h"
|
||||
#include "GridCell.h"
|
||||
#include "MapGrid.h"
|
||||
|
||||
// Forward class definitions
|
||||
class Corpse;
|
||||
@@ -31,8 +32,6 @@ class Pet;
|
||||
class Player;
|
||||
class ObjectGuid;
|
||||
|
||||
#define MAX_NUMBER_OF_CELLS 8
|
||||
|
||||
#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2)
|
||||
|
||||
#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2)
|
||||
@@ -73,8 +72,8 @@ enum GridMapTypeMask
|
||||
GRID_MAP_TYPE_MASK_ALL = 0x1F
|
||||
};
|
||||
|
||||
typedef Grid<Player, AllWorldObjectTypes, AllGridObjectTypes> GridType;
|
||||
typedef NGrid<MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType;
|
||||
typedef GridCell<AllWorldObjectTypes, AllGridObjectTypes> GridCellType;
|
||||
typedef MapGrid<AllWorldObjectTypes, AllGridObjectTypes> MapGridType;
|
||||
|
||||
typedef TypeMapContainer<AllGridObjectTypes> GridTypeMapContainer;
|
||||
typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer;
|
||||
@@ -171,37 +170,29 @@ typedef CoordPair<TOTAL_NUMBER_OF_CELLS_PER_MAP> CellCoord;
|
||||
namespace Acore
|
||||
{
|
||||
template<class RET_TYPE, int CENTER_VAL>
|
||||
inline RET_TYPE Compute(float x, float y, float center_offset, float size)
|
||||
inline RET_TYPE Compute(float x, float y, float size)
|
||||
{
|
||||
// calculate and store temporary values in double format for having same result as same mySQL calculations
|
||||
double x_offset = (double(x) - center_offset) / size;
|
||||
double y_offset = (double(y) - center_offset) / size;
|
||||
int gx = (int)(CENTER_VAL - x / size);
|
||||
int gy = (int)(CENTER_VAL - y / size);
|
||||
|
||||
int x_val = int(x_offset + CENTER_VAL + 0.5f);
|
||||
int y_val = int(y_offset + CENTER_VAL + 0.5f);
|
||||
return RET_TYPE(x_val, y_val);
|
||||
return RET_TYPE(gx, gy);
|
||||
}
|
||||
|
||||
inline GridCoord ComputeGridCoord(float x, float y)
|
||||
{
|
||||
return Compute<GridCoord, CENTER_GRID_ID>(x, y, CENTER_GRID_OFFSET, SIZE_OF_GRIDS);
|
||||
return Compute<GridCoord, CENTER_GRID_ID>(x, y, SIZE_OF_GRIDS);
|
||||
}
|
||||
|
||||
inline GridCoord ComputeGridCoordSimple(float x, float y)
|
||||
{
|
||||
int gx = (int)(CENTER_GRID_ID - x / SIZE_OF_GRIDS);
|
||||
int gy = (int)(CENTER_GRID_ID - y / SIZE_OF_GRIDS);
|
||||
return GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy);
|
||||
}
|
||||
|
||||
inline CellCoord ComputeCellCoord(float x, float y)
|
||||
{
|
||||
return Compute<CellCoord, CENTER_GRID_CELL_ID>(x, y, CENTER_GRID_CELL_OFFSET, SIZE_OF_GRID_CELL);
|
||||
}
|
||||
|
||||
inline CellCoord ComputeCellCoord(float x, float y, float& x_off, float& y_off)
|
||||
{
|
||||
double x_offset = (double(x) - CENTER_GRID_CELL_OFFSET) / SIZE_OF_GRID_CELL;
|
||||
double y_offset = (double(y) - CENTER_GRID_CELL_OFFSET) / SIZE_OF_GRID_CELL;
|
||||
|
||||
int x_val = int(x_offset + CENTER_GRID_CELL_ID + 0.5f);
|
||||
int y_val = int(y_offset + CENTER_GRID_CELL_ID + 0.5f);
|
||||
x_off = (float(x_offset) - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
|
||||
y_off = (float(y_offset) - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
|
||||
return CellCoord(x_val, y_val);
|
||||
return Compute<CellCoord, CENTER_GRID_CELL_ID>(x, y, SIZE_OF_GRID_CELL);
|
||||
}
|
||||
|
||||
inline void NormalizeMapCoord(float& c)
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACORE_GRIDLOADER_H
|
||||
#define ACORE_GRIDLOADER_H
|
||||
|
||||
/**
|
||||
@class GridLoader
|
||||
The GridLoader is working in conjuction with the Grid and responsible
|
||||
for loading and unloading object-types (one or more) when objects
|
||||
enters a grid. Unloading is scheduled and might be canceled if
|
||||
an interested object re-enters. GridLoader does not do the actuall
|
||||
loading and unloading but implements as a template pattern that
|
||||
delicate its loading and unloading for the actualy loader and unloader.
|
||||
GridLoader manages the grid (both local and remote).
|
||||
*/
|
||||
|
||||
//I cannot see why this cannot be replaced by a Grid::Visit
|
||||
/*
|
||||
#include "Define.h"
|
||||
#include "Grid.h"
|
||||
#include "TypeContainerVisitor.h"
|
||||
|
||||
template
|
||||
<
|
||||
class ACTIVE_OBJECT,
|
||||
class WORLD_OBJECT_TYPES,
|
||||
class GRID_OBJECT_TYPES
|
||||
>
|
||||
class GridLoader
|
||||
{
|
||||
public:
|
||||
|
||||
// Loads the grid
|
||||
template<class LOADER>
|
||||
void Load(Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> &grid, LOADER &loader)
|
||||
{
|
||||
grid.LockGrid();
|
||||
loader.Load(grid);
|
||||
grid.UnlockGrid();
|
||||
}
|
||||
|
||||
// Stop the grid
|
||||
template<class STOPER>
|
||||
void Stop(Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> &grid, STOPER &stoper)
|
||||
{
|
||||
grid.LockGrid();
|
||||
stoper.Stop(grid);
|
||||
grid.UnlockGrid();
|
||||
}
|
||||
|
||||
// Unloads the grid
|
||||
template<class UNLOADER>
|
||||
void Unload(Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> &grid, UNLOADER &unloader)
|
||||
{
|
||||
grid.LockGrid();
|
||||
unloader.Unload(grid);
|
||||
grid.UnlockGrid();
|
||||
}
|
||||
};
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GridObjectLoader.h"
|
||||
#include "CellImpl.h"
|
||||
#include "Corpse.h"
|
||||
#include "Creature.h"
|
||||
#include "DynamicObject.h"
|
||||
#include "GameObject.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "Transport.h"
|
||||
|
||||
template <class T>
|
||||
void GridObjectLoader::AddObjectHelper(Map* map, T* obj)
|
||||
{
|
||||
CellCoord cellCoord = Acore::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY());
|
||||
Cell cell(cellCoord);
|
||||
|
||||
map->AddToGrid(obj, cell);
|
||||
obj->AddToWorld();
|
||||
if (obj->isActiveObject())
|
||||
map->AddToActive(obj);
|
||||
}
|
||||
|
||||
void GridObjectLoader::LoadCreatures(CellGuidSet const& guid_set, Map* map)
|
||||
{
|
||||
for (ObjectGuid::LowType const& guid : guid_set)
|
||||
{
|
||||
Creature* obj = new Creature();
|
||||
if (!obj->LoadFromDB(guid, map))
|
||||
{
|
||||
delete obj;
|
||||
continue;
|
||||
}
|
||||
|
||||
AddObjectHelper<Creature>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GridObjectLoader::LoadGameObjects(CellGuidSet const& guid_set, Map* map)
|
||||
{
|
||||
for (ObjectGuid::LowType const& guid : guid_set)
|
||||
{
|
||||
GameObjectData const* data = sObjectMgr->GetGameObjectData(guid);
|
||||
GameObject* obj = data && sObjectMgr->IsGameObjectStaticTransport(data->id) ? new StaticTransport() : new GameObject();
|
||||
|
||||
if (!obj->LoadFromDB(guid, map))
|
||||
{
|
||||
delete obj;
|
||||
continue;
|
||||
}
|
||||
|
||||
AddObjectHelper<GameObject>(map, obj);
|
||||
}
|
||||
}
|
||||
|
||||
void GridObjectLoader::LoadAllCellsInGrid()
|
||||
{
|
||||
CellObjectGuids const& cell_guids = sObjectMgr->GetGridObjectGuids(_map->GetId(), _map->GetSpawnMode(), _grid.GetId());
|
||||
LoadGameObjects(cell_guids.gameobjects, _map);
|
||||
LoadCreatures(cell_guids.creatures, _map);
|
||||
|
||||
if (std::unordered_set<Corpse*> const* corpses = _map->GetCorpsesInCell(_grid.GetId()))
|
||||
{
|
||||
for (Corpse* corpse : *corpses)
|
||||
{
|
||||
if (corpse->IsInGrid())
|
||||
continue;
|
||||
|
||||
CellCoord cellCoord = Acore::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY());
|
||||
Cell cell(cellCoord);
|
||||
|
||||
if (corpse->IsWorldObject())
|
||||
_grid.AddWorldObject(cell.CellX(), cell.CellY(), corpse);
|
||||
else
|
||||
_grid.AddGridObject(cell.CellX(), cell.CellY(), corpse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void GridObjectUnloader::Visit(GridRefMgr<T>& m)
|
||||
{
|
||||
while (!m.IsEmpty())
|
||||
{
|
||||
T* obj = m.getFirst()->GetSource();
|
||||
// if option set then object already saved at this moment
|
||||
//if (!sWorld->getBoolConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY))
|
||||
// obj->SaveRespawnTime();
|
||||
//Some creatures may summon other temp summons in CleanupsBeforeDelete()
|
||||
//So we need this even after cleaner (maybe we can remove cleaner)
|
||||
//Example: Flame Leviathan Turret 33139 is summoned when a creature is deleted
|
||||
//TODO: Check if that script has the correct logic. Do we really need to summons something before deleting?
|
||||
obj->CleanupsBeforeDelete();
|
||||
///- object will get delinked from the manager when deleted
|
||||
delete obj;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void GridObjectCleaner::Visit(GridRefMgr<T>& m)
|
||||
{
|
||||
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
iter->GetSource()->CleanupsBeforeDelete();
|
||||
}
|
||||
|
||||
template void GridObjectUnloader::Visit(CreatureMapType&);
|
||||
template void GridObjectUnloader::Visit(GameObjectMapType&);
|
||||
template void GridObjectUnloader::Visit(DynamicObjectMapType&);
|
||||
|
||||
template void GridObjectCleaner::Visit(CreatureMapType&);
|
||||
template void GridObjectCleaner::Visit<GameObject>(GameObjectMapType&);
|
||||
template void GridObjectCleaner::Visit<DynamicObject>(DynamicObjectMapType&);
|
||||
template void GridObjectCleaner::Visit<Corpse>(CorpseMapType&);
|
||||
+19
-28
@@ -15,51 +15,42 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACORE_OBJECTGRIDLOADER_H
|
||||
#define ACORE_OBJECTGRIDLOADER_H
|
||||
#ifndef ACORE_GRID_OBJECT_LOADER_H
|
||||
#define ACORE_GRID_OBJECT_LOADER_H
|
||||
|
||||
#include "Cell.h"
|
||||
#include "Define.h"
|
||||
#include "GridDefines.h"
|
||||
#include "ObjectMgr.h"
|
||||
|
||||
class ObjectWorldLoader;
|
||||
|
||||
class ObjectGridLoader
|
||||
class GridObjectLoader
|
||||
{
|
||||
friend class ObjectWorldLoader;
|
||||
|
||||
public:
|
||||
ObjectGridLoader(NGridType& grid, Map* map, const Cell& cell)
|
||||
: i_cell(cell), i_grid(grid), i_map(map), i_gameObjects(0), i_creatures(0), i_corpses (0)
|
||||
{}
|
||||
GridObjectLoader(MapGridType& grid, Map* map)
|
||||
: _grid(grid), _map(map) { }
|
||||
|
||||
void Visit(GameObjectMapType& m);
|
||||
void Visit(CreatureMapType& m);
|
||||
void Visit(CorpseMapType&) const {}
|
||||
void Visit(DynamicObjectMapType&) const {}
|
||||
|
||||
void LoadN(void);
|
||||
|
||||
template<class T> static void SetObjectCell(T* obj, CellCoord const& cellCoord);
|
||||
void LoadAllCellsInGrid();
|
||||
|
||||
private:
|
||||
Cell i_cell;
|
||||
NGridType& i_grid;
|
||||
Map* i_map;
|
||||
uint32 i_gameObjects;
|
||||
uint32 i_creatures;
|
||||
uint32 i_corpses;
|
||||
template<class T>
|
||||
void AddObjectHelper(Map* map, T* obj);
|
||||
|
||||
void LoadCreatures(CellGuidSet const& guid_set, Map* map);
|
||||
void LoadGameObjects(CellGuidSet const& guid_set, Map* map);
|
||||
|
||||
MapGridType& _grid;
|
||||
Map* _map;
|
||||
};
|
||||
|
||||
//Clean up and remove from world
|
||||
class ObjectGridCleaner
|
||||
// Clean up and remove from world
|
||||
class GridObjectCleaner
|
||||
{
|
||||
public:
|
||||
template<class T> void Visit(GridRefMgr<T>&);
|
||||
};
|
||||
|
||||
//Delete objects before deleting NGrid
|
||||
class ObjectGridUnloader
|
||||
// Delete objects before deleting NGrid
|
||||
class GridObjectUnloader
|
||||
{
|
||||
public:
|
||||
void Visit(CorpseMapType&) { } // corpses are deleted with Map
|
||||
@@ -0,0 +1,617 @@
|
||||
#include "DBCStores.h"
|
||||
#include "GridDefines.h"
|
||||
#include "GridTerrainData.h"
|
||||
#include "Log.h"
|
||||
#include "MapDefines.h"
|
||||
#include <filesystem>
|
||||
#include <G3D/Ray.h>
|
||||
|
||||
uint16 const holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 };
|
||||
uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
|
||||
|
||||
GridTerrainData::GridTerrainData()
|
||||
{
|
||||
_gridGetHeight = &GridTerrainData::getHeightFromFlat;
|
||||
}
|
||||
|
||||
TerrainMapDataReadResult GridTerrainData::Load(std::string const& mapFileName)
|
||||
{
|
||||
// Check if file exists, we do this first as we need to
|
||||
// differentiate between file existing and any other file errors
|
||||
if (!std::filesystem::exists(mapFileName))
|
||||
return TerrainMapDataReadResult::NotFound;
|
||||
|
||||
// Start the input stream and check for any errors
|
||||
std::ifstream fileStream(mapFileName, std::ios::binary);
|
||||
if (fileStream.fail())
|
||||
return TerrainMapDataReadResult::ReadError;
|
||||
|
||||
// Read the map header
|
||||
map_fileheader header;
|
||||
if (!fileStream.read(reinterpret_cast<char*>(&header), sizeof(header)))
|
||||
return TerrainMapDataReadResult::ReadError;
|
||||
|
||||
// Check for valid map and version magics
|
||||
if (header.mapMagic != MapMagic.asUInt || header.versionMagic != MapVersionMagic)
|
||||
return TerrainMapDataReadResult::InvalidMagic;
|
||||
|
||||
// Load area data
|
||||
if (header.areaMapOffset && !LoadAreaData(fileStream, header.areaMapOffset))
|
||||
return TerrainMapDataReadResult::InvalidAreaData;
|
||||
|
||||
// Load height data
|
||||
if (header.heightMapOffset && !LoadHeightData(fileStream, header.heightMapOffset))
|
||||
return TerrainMapDataReadResult::InvalidHeightData;
|
||||
|
||||
// Load liquid data
|
||||
if (header.liquidMapOffset && !LoadLiquidData(fileStream, header.liquidMapOffset))
|
||||
return TerrainMapDataReadResult::InvalidLiquidData;
|
||||
|
||||
// Load hole data
|
||||
if (header.holesSize && !LoadHolesData(fileStream, header.holesOffset))
|
||||
return TerrainMapDataReadResult::InvalidHoleData;
|
||||
|
||||
return TerrainMapDataReadResult::Success;
|
||||
}
|
||||
|
||||
bool GridTerrainData::LoadAreaData(std::ifstream& fileStream, uint32 const offset)
|
||||
{
|
||||
fileStream.seekg(offset);
|
||||
|
||||
map_areaHeader header;
|
||||
if (!fileStream.read(reinterpret_cast<char*>(&header), sizeof(header)) || header.fourcc != MapAreaMagic.asUInt)
|
||||
return false;
|
||||
|
||||
_loadedAreaData = std::make_unique<LoadedAreaData>();
|
||||
_loadedAreaData->gridArea = header.gridArea;
|
||||
if (!(header.flags & MAP_AREA_NO_AREA))
|
||||
{
|
||||
_loadedAreaData->areaMap = std::make_unique<LoadedAreaData::AreaMapType>();
|
||||
if (!fileStream.read(reinterpret_cast<char*>(_loadedAreaData->areaMap.get()), sizeof(LoadedAreaData::AreaMapType)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GridTerrainData::LoadHeightData(std::ifstream& fileStream, uint32 const offset)
|
||||
{
|
||||
fileStream.seekg(offset);
|
||||
|
||||
map_heightHeader header;
|
||||
if (!fileStream.read(reinterpret_cast<char*>(&header), sizeof(header)) || header.fourcc != MapHeightMagic.asUInt)
|
||||
return false;
|
||||
|
||||
_loadedHeightData = std::make_unique<LoadedHeightData>();
|
||||
_loadedHeightData->gridHeight = header.gridHeight;
|
||||
if (!(header.flags & MAP_HEIGHT_NO_HEIGHT))
|
||||
{
|
||||
if ((header.flags & MAP_HEIGHT_AS_INT16))
|
||||
{
|
||||
_loadedHeightData->uint16HeightData = std::make_unique<LoadedHeightData::Uint16HeightData>();
|
||||
if (!fileStream.read(reinterpret_cast<char*>(&_loadedHeightData->uint16HeightData->v9), sizeof(_loadedHeightData->uint16HeightData->v9))
|
||||
|| !fileStream.read(reinterpret_cast<char*>(&_loadedHeightData->uint16HeightData->v8), sizeof(_loadedHeightData->uint16HeightData->v8)))
|
||||
return false;
|
||||
|
||||
_loadedHeightData->uint16HeightData->gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535;
|
||||
_gridGetHeight = &GridTerrainData::getHeightFromUint16;
|
||||
}
|
||||
else if ((header.flags & MAP_HEIGHT_AS_INT8))
|
||||
{
|
||||
_loadedHeightData->uint8HeightData = std::make_unique<LoadedHeightData::Uint8HeightData>();
|
||||
if (!fileStream.read(reinterpret_cast<char*>(&_loadedHeightData->uint8HeightData->v9), sizeof(_loadedHeightData->uint8HeightData->v9))
|
||||
|| !fileStream.read(reinterpret_cast<char*>(&_loadedHeightData->uint8HeightData->v8), sizeof(_loadedHeightData->uint8HeightData->v8)))
|
||||
return false;
|
||||
|
||||
_loadedHeightData->uint8HeightData->gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255;
|
||||
_gridGetHeight = &GridTerrainData::getHeightFromUint8;
|
||||
}
|
||||
else
|
||||
{
|
||||
_loadedHeightData->floatHeightData = std::make_unique<LoadedHeightData::FloatHeightData>();
|
||||
if (!fileStream.read(reinterpret_cast<char*>(&_loadedHeightData->floatHeightData->v9), sizeof(_loadedHeightData->floatHeightData->v9))
|
||||
|| !fileStream.read(reinterpret_cast<char*>(&_loadedHeightData->floatHeightData->v8), sizeof(_loadedHeightData->floatHeightData->v8)))
|
||||
return false;
|
||||
|
||||
_gridGetHeight = &GridTerrainData::getHeightFromFloat;
|
||||
}
|
||||
}
|
||||
else
|
||||
_gridGetHeight = &GridTerrainData::getHeightFromFlat;
|
||||
|
||||
if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
|
||||
{
|
||||
std::array<int16, 9> maxHeights;
|
||||
std::array<int16, 9> minHeights;
|
||||
if (!fileStream.read(reinterpret_cast<char*>(maxHeights.data()), sizeof(maxHeights)) ||
|
||||
!fileStream.read(reinterpret_cast<char*>(minHeights.data()), sizeof(minHeights)))
|
||||
return false;
|
||||
|
||||
static uint32 constexpr indices[8][3] =
|
||||
{
|
||||
{ 3, 0, 4 },
|
||||
{ 0, 1, 4 },
|
||||
{ 1, 2, 4 },
|
||||
{ 2, 5, 4 },
|
||||
{ 5, 8, 4 },
|
||||
{ 8, 7, 4 },
|
||||
{ 7, 6, 4 },
|
||||
{ 6, 3, 4 }
|
||||
};
|
||||
|
||||
static float constexpr boundGridCoords[9][2] =
|
||||
{
|
||||
{ 0.0f, 0.0f },
|
||||
{ 0.0f, -266.66666f },
|
||||
{ 0.0f, -533.33331f },
|
||||
{ -266.66666f, 0.0f },
|
||||
{ -266.66666f, -266.66666f },
|
||||
{ -266.66666f, -533.33331f },
|
||||
{ -533.33331f, 0.0f },
|
||||
{ -533.33331f, -266.66666f },
|
||||
{ -533.33331f, -533.33331f }
|
||||
};
|
||||
|
||||
_loadedHeightData->minHeightPlanes = std::make_unique<LoadedHeightData::HeightPlanesType>();
|
||||
for (uint32 quarterIndex = 0; quarterIndex < _loadedHeightData->minHeightPlanes->size(); ++quarterIndex)
|
||||
_loadedHeightData->minHeightPlanes->at(quarterIndex) = G3D::Plane(
|
||||
G3D::Vector3(boundGridCoords[indices[quarterIndex][0]][0], boundGridCoords[indices[quarterIndex][0]][1], minHeights[indices[quarterIndex][0]]),
|
||||
G3D::Vector3(boundGridCoords[indices[quarterIndex][1]][0], boundGridCoords[indices[quarterIndex][1]][1], minHeights[indices[quarterIndex][1]]),
|
||||
G3D::Vector3(boundGridCoords[indices[quarterIndex][2]][0], boundGridCoords[indices[quarterIndex][2]][1], minHeights[indices[quarterIndex][2]])
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GridTerrainData::LoadLiquidData(std::ifstream& fileStream, uint32 const offset)
|
||||
{
|
||||
fileStream.seekg(offset);
|
||||
|
||||
map_liquidHeader header;
|
||||
if (!fileStream.read(reinterpret_cast<char*>(&header), sizeof(header)) || header.fourcc != MapLiquidMagic.asUInt)
|
||||
return false;
|
||||
|
||||
_loadedLiquidData = std::make_unique<LoadedLiquidData>();
|
||||
_loadedLiquidData->liquidGlobalEntry = header.liquidType;
|
||||
_loadedLiquidData->liquidGlobalFlags = header.liquidFlags;
|
||||
_loadedLiquidData->liquidOffX = header.offsetX;
|
||||
_loadedLiquidData->liquidOffY = header.offsetY;
|
||||
_loadedLiquidData->liquidWidth = header.width;
|
||||
_loadedLiquidData->liquidHeight = header.height;
|
||||
_loadedLiquidData->liquidLevel = header.liquidLevel;
|
||||
|
||||
if (!(header.flags & MAP_LIQUID_NO_TYPE))
|
||||
{
|
||||
_loadedLiquidData->liquidEntry = std::make_unique<LoadedLiquidData::LiquidEntryType>();
|
||||
if (!fileStream.read(reinterpret_cast<char*>(_loadedLiquidData->liquidEntry.get()), sizeof(LoadedLiquidData::LiquidEntryType)))
|
||||
return false;
|
||||
|
||||
_loadedLiquidData->liquidFlags = std::make_unique<LoadedLiquidData::LiquidFlagsType>();
|
||||
if (!fileStream.read(reinterpret_cast<char*>(_loadedLiquidData->liquidFlags.get()), sizeof(LoadedLiquidData::LiquidFlagsType)))
|
||||
return false;
|
||||
}
|
||||
if (!(header.flags & MAP_LIQUID_NO_HEIGHT))
|
||||
{
|
||||
_loadedLiquidData->liquidMap = std::make_unique<LoadedLiquidData::LiquidMapType>();
|
||||
_loadedLiquidData->liquidMap->resize(_loadedLiquidData->liquidWidth * _loadedLiquidData->liquidHeight);
|
||||
if (!fileStream.read(reinterpret_cast<char*>(_loadedLiquidData->liquidMap->data()), _loadedLiquidData->liquidMap->size() * sizeof(float)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GridTerrainData::LoadHolesData(std::ifstream& fileStream, uint32 const offset)
|
||||
{
|
||||
fileStream.seekg(offset);
|
||||
|
||||
_loadedHoleData = std::make_unique<LoadedHoleData>();
|
||||
if (!fileStream.read(reinterpret_cast<char*>(&_loadedHoleData->holes), sizeof(_loadedHoleData->holes)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 GridTerrainData::getArea(float x, float y) const
|
||||
{
|
||||
if (!_loadedAreaData)
|
||||
return 0;
|
||||
|
||||
if (!_loadedAreaData->areaMap)
|
||||
return _loadedAreaData->gridArea;
|
||||
|
||||
x = 16 * (32 - x / SIZE_OF_GRIDS);
|
||||
y = 16 * (32 - y / SIZE_OF_GRIDS);
|
||||
int lx = (int)x & 15;
|
||||
int ly = (int)y & 15;
|
||||
return _loadedAreaData->areaMap->at(lx * 16 + ly);
|
||||
}
|
||||
|
||||
float GridTerrainData::getHeightFromFlat(float /*x*/, float /*y*/) const
|
||||
{
|
||||
if (!_loadedHeightData)
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
return _loadedHeightData->gridHeight;
|
||||
}
|
||||
|
||||
float GridTerrainData::getHeightFromFloat(float x, float y) const
|
||||
{
|
||||
if (!_loadedHeightData || !_loadedHeightData->floatHeightData)
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
||||
y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
||||
|
||||
int x_int = (int)x;
|
||||
int y_int = (int)y;
|
||||
x -= x_int;
|
||||
y -= y_int;
|
||||
x_int &= (MAP_RESOLUTION - 1);
|
||||
y_int &= (MAP_RESOLUTION - 1);
|
||||
|
||||
if (isHole(x_int, y_int))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
// Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
|
||||
// +--------------> X
|
||||
// | h1-------h2 Coordinates is:
|
||||
// | | \ 1 / | h1 0, 0
|
||||
// | | \ / | h2 0, 1
|
||||
// | | 2 h5 3 | h3 1, 0
|
||||
// | | / \ | h4 1, 1
|
||||
// | | / 4 \ | h5 1/2, 1/2
|
||||
// | h3-------h4
|
||||
// V Y
|
||||
// For find height need
|
||||
// 1 - detect triangle
|
||||
// 2 - solve linear equation from triangle points
|
||||
// Calculate coefficients for solve h = a*x + b*y + c
|
||||
|
||||
float a, b, c;
|
||||
// Select triangle:
|
||||
if (x + y < 1)
|
||||
{
|
||||
if (x > y)
|
||||
{
|
||||
// 1 triangle (h1, h2, h5 points)
|
||||
float h1 = _loadedHeightData->floatHeightData->v9[(x_int) * 129 + y_int];
|
||||
float h2 = _loadedHeightData->floatHeightData->v9[(x_int + 1) * 129 + y_int];
|
||||
float h5 = 2 * _loadedHeightData->floatHeightData->v8[x_int * 128 + y_int];
|
||||
a = h2 - h1;
|
||||
b = h5 - h1 - h2;
|
||||
c = h1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2 triangle (h1, h3, h5 points)
|
||||
float h1 = _loadedHeightData->floatHeightData->v9[x_int * 129 + y_int];
|
||||
float h3 = _loadedHeightData->floatHeightData->v9[x_int * 129 + y_int + 1];
|
||||
float h5 = 2 * _loadedHeightData->floatHeightData->v8[x_int * 128 + y_int];
|
||||
a = h5 - h1 - h3;
|
||||
b = h3 - h1;
|
||||
c = h1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x > y)
|
||||
{
|
||||
// 3 triangle (h2, h4, h5 points)
|
||||
float h2 = _loadedHeightData->floatHeightData->v9[(x_int + 1) * 129 + y_int];
|
||||
float h4 = _loadedHeightData->floatHeightData->v9[(x_int + 1) * 129 + y_int + 1];
|
||||
float h5 = 2 * _loadedHeightData->floatHeightData->v8[x_int * 128 + y_int];
|
||||
a = h2 + h4 - h5;
|
||||
b = h4 - h2;
|
||||
c = h5 - h4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4 triangle (h3, h4, h5 points)
|
||||
float h3 = _loadedHeightData->floatHeightData->v9[(x_int) * 129 + y_int + 1];
|
||||
float h4 = _loadedHeightData->floatHeightData->v9[(x_int + 1) * 129 + y_int + 1];
|
||||
float h5 = 2 * _loadedHeightData->floatHeightData->v8[x_int * 128 + y_int];
|
||||
a = h4 - h3;
|
||||
b = h3 + h4 - h5;
|
||||
c = h5 - h4;
|
||||
}
|
||||
}
|
||||
// Calculate height
|
||||
return a * x + b * y + c;
|
||||
}
|
||||
|
||||
float GridTerrainData::getHeightFromUint8(float x, float y) const
|
||||
{
|
||||
if (!_loadedHeightData || !_loadedHeightData->uint8HeightData)
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
||||
y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
||||
|
||||
int x_int = (int)x;
|
||||
int y_int = (int)y;
|
||||
x -= x_int;
|
||||
y -= y_int;
|
||||
x_int &= (MAP_RESOLUTION - 1);
|
||||
y_int &= (MAP_RESOLUTION - 1);
|
||||
|
||||
if (isHole(x_int, y_int))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
int32 a, b, c;
|
||||
uint8* V9_h1_ptr = &_loadedHeightData->uint8HeightData->v9[x_int * 128 + x_int + y_int];
|
||||
if (x + y < 1)
|
||||
{
|
||||
if (x > y)
|
||||
{
|
||||
// 1 triangle (h1, h2, h5 points)
|
||||
int32 h1 = V9_h1_ptr[0];
|
||||
int32 h2 = V9_h1_ptr[129];
|
||||
int32 h5 = 2 * _loadedHeightData->uint8HeightData->v8[x_int * 128 + y_int];
|
||||
a = h2 - h1;
|
||||
b = h5 - h1 - h2;
|
||||
c = h1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2 triangle (h1, h3, h5 points)
|
||||
int32 h1 = V9_h1_ptr[0];
|
||||
int32 h3 = V9_h1_ptr[1];
|
||||
int32 h5 = 2 * _loadedHeightData->uint8HeightData->v8[x_int * 128 + y_int];
|
||||
a = h5 - h1 - h3;
|
||||
b = h3 - h1;
|
||||
c = h1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x > y)
|
||||
{
|
||||
// 3 triangle (h2, h4, h5 points)
|
||||
int32 h2 = V9_h1_ptr[129];
|
||||
int32 h4 = V9_h1_ptr[130];
|
||||
int32 h5 = 2 * _loadedHeightData->uint8HeightData->v8[x_int * 128 + y_int];
|
||||
a = h2 + h4 - h5;
|
||||
b = h4 - h2;
|
||||
c = h5 - h4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4 triangle (h3, h4, h5 points)
|
||||
int32 h3 = V9_h1_ptr[1];
|
||||
int32 h4 = V9_h1_ptr[130];
|
||||
int32 h5 = 2 * _loadedHeightData->uint8HeightData->v8[x_int * 128 + y_int];
|
||||
a = h4 - h3;
|
||||
b = h3 + h4 - h5;
|
||||
c = h5 - h4;
|
||||
}
|
||||
}
|
||||
// Calculate height
|
||||
return (float)((a * x) + (b * y) + c) * _loadedHeightData->uint8HeightData->gridIntHeightMultiplier + _loadedHeightData->gridHeight;
|
||||
}
|
||||
|
||||
float GridTerrainData::getHeightFromUint16(float x, float y) const
|
||||
{
|
||||
if (!_loadedHeightData || !_loadedHeightData->uint16HeightData)
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
||||
y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
||||
|
||||
int x_int = (int)x;
|
||||
int y_int = (int)y;
|
||||
x -= x_int;
|
||||
y -= y_int;
|
||||
x_int &= (MAP_RESOLUTION - 1);
|
||||
y_int &= (MAP_RESOLUTION - 1);
|
||||
|
||||
if (isHole(x_int, y_int))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
int32 a, b, c;
|
||||
uint16* V9_h1_ptr = &_loadedHeightData->uint16HeightData->v9[x_int * 128 + x_int + y_int];
|
||||
if (x + y < 1)
|
||||
{
|
||||
if (x > y)
|
||||
{
|
||||
// 1 triangle (h1, h2, h5 points)
|
||||
int32 h1 = V9_h1_ptr[0];
|
||||
int32 h2 = V9_h1_ptr[129];
|
||||
int32 h5 = 2 * _loadedHeightData->uint16HeightData->v8[x_int * 128 + y_int];
|
||||
a = h2 - h1;
|
||||
b = h5 - h1 - h2;
|
||||
c = h1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2 triangle (h1, h3, h5 points)
|
||||
int32 h1 = V9_h1_ptr[0];
|
||||
int32 h3 = V9_h1_ptr[1];
|
||||
int32 h5 = 2 * _loadedHeightData->uint16HeightData->v8[x_int * 128 + y_int];
|
||||
a = h5 - h1 - h3;
|
||||
b = h3 - h1;
|
||||
c = h1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x > y)
|
||||
{
|
||||
// 3 triangle (h2, h4, h5 points)
|
||||
int32 h2 = V9_h1_ptr[129];
|
||||
int32 h4 = V9_h1_ptr[130];
|
||||
int32 h5 = 2 * _loadedHeightData->uint16HeightData->v8[x_int * 128 + y_int];
|
||||
a = h2 + h4 - h5;
|
||||
b = h4 - h2;
|
||||
c = h5 - h4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4 triangle (h3, h4, h5 points)
|
||||
int32 h3 = V9_h1_ptr[1];
|
||||
int32 h4 = V9_h1_ptr[130];
|
||||
int32 h5 = 2 * _loadedHeightData->uint16HeightData->v8[x_int * 128 + y_int];
|
||||
a = h4 - h3;
|
||||
b = h3 + h4 - h5;
|
||||
c = h5 - h4;
|
||||
}
|
||||
}
|
||||
// Calculate height
|
||||
return (float)((a * x) + (b * y) + c) * _loadedHeightData->uint16HeightData->gridIntHeightMultiplier + _loadedHeightData->gridHeight;
|
||||
}
|
||||
|
||||
bool GridTerrainData::isHole(int row, int col) const
|
||||
{
|
||||
if (!_loadedHoleData)
|
||||
return false;
|
||||
|
||||
int cellRow = row / 8; // 8 squares per cell
|
||||
int cellCol = col / 8;
|
||||
int holeRow = row % 8 / 2;
|
||||
int holeCol = (col - (cellCol * 8)) / 2;
|
||||
|
||||
uint16 hole = _loadedHoleData->holes[cellRow * 16 + cellCol];
|
||||
|
||||
return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0;
|
||||
}
|
||||
|
||||
float GridTerrainData::getMinHeight(float x, float y) const
|
||||
{
|
||||
if (!_loadedHeightData || !_loadedHeightData->minHeightPlanes)
|
||||
return MIN_HEIGHT;
|
||||
|
||||
GridCoord gridCoord = Acore::ComputeGridCoordSimple(x, y);
|
||||
|
||||
int32 doubleGridX = int32(std::floor(-(x - MAP_HALFSIZE) / CENTER_GRID_OFFSET));
|
||||
int32 doubleGridY = int32(std::floor(-(y - MAP_HALFSIZE) / CENTER_GRID_OFFSET));
|
||||
|
||||
float gx = x - (int32(gridCoord.x_coord) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
|
||||
float gy = y - (int32(gridCoord.y_coord) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
|
||||
|
||||
uint32 quarterIndex = 0;
|
||||
if (doubleGridY & 1)
|
||||
{
|
||||
if (doubleGridX & 1)
|
||||
quarterIndex = 4 + (gx <= gy);
|
||||
else
|
||||
quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy);
|
||||
}
|
||||
else if (doubleGridX & 1)
|
||||
quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy);
|
||||
else
|
||||
quarterIndex = gx > gy;
|
||||
|
||||
G3D::Ray ray = G3D::Ray::fromOriginAndDirection(G3D::Vector3(gx, gy, 0.0f), G3D::Vector3::unitZ());
|
||||
return ray.intersection(_loadedHeightData->minHeightPlanes->at(quarterIndex)).z;
|
||||
}
|
||||
|
||||
float GridTerrainData::getLiquidLevel(float x, float y) const
|
||||
{
|
||||
if (!_loadedLiquidData)
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
if (!_loadedLiquidData->liquidMap)
|
||||
return _loadedLiquidData->liquidLevel;
|
||||
|
||||
x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
||||
y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
||||
|
||||
int cx_int = ((int)x & (MAP_RESOLUTION - 1)) - _loadedLiquidData->liquidOffY;
|
||||
int cy_int = ((int)y & (MAP_RESOLUTION - 1)) - _loadedLiquidData->liquidOffX;
|
||||
|
||||
if (cx_int < 0 || cx_int >= _loadedLiquidData->liquidHeight)
|
||||
return INVALID_HEIGHT;
|
||||
if (cy_int < 0 || cy_int >= _loadedLiquidData->liquidWidth)
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
return _loadedLiquidData->liquidMap->at(cx_int * _loadedLiquidData->liquidWidth + cy_int);
|
||||
}
|
||||
|
||||
// Get water state on map
|
||||
LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const
|
||||
{
|
||||
LiquidData liquidData;
|
||||
if (!_loadedLiquidData)
|
||||
return liquidData;
|
||||
|
||||
// Check water type (if no water return)
|
||||
if (_loadedLiquidData->liquidGlobalFlags || _loadedLiquidData->liquidFlags)
|
||||
{
|
||||
// Get cell
|
||||
float cx = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
||||
float cy = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
||||
|
||||
int x_int = (int)cx & (MAP_RESOLUTION - 1);
|
||||
int y_int = (int)cy & (MAP_RESOLUTION - 1);
|
||||
|
||||
// Check water type in cell
|
||||
int idx = (x_int >> 3) * 16 + (y_int >> 3);
|
||||
uint8 type = _loadedLiquidData->liquidFlags ? _loadedLiquidData->liquidFlags->at(idx) : _loadedLiquidData->liquidGlobalFlags;
|
||||
uint32 entry = _loadedLiquidData->liquidEntry ? _loadedLiquidData->liquidEntry->at(idx) : _loadedLiquidData->liquidGlobalEntry;
|
||||
if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(entry))
|
||||
{
|
||||
type &= MAP_LIQUID_TYPE_DARK_WATER;
|
||||
uint32 liqTypeIdx = liquidEntry->Type;
|
||||
if (entry < 21)
|
||||
{
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
|
||||
{
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
}
|
||||
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||
{
|
||||
entry = overrideLiquid;
|
||||
liqTypeIdx = liq->Type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type |= 1 << liqTypeIdx;
|
||||
}
|
||||
|
||||
// Check req liquid type mask
|
||||
if (type != 0 && (!ReqLiquidType || (ReqLiquidType & type) != 0))
|
||||
{
|
||||
// Check water level:
|
||||
// Check water height map
|
||||
int lx_int = x_int - _loadedLiquidData->liquidOffY;
|
||||
int ly_int = y_int - _loadedLiquidData->liquidOffX;
|
||||
if (lx_int >= 0 && lx_int < _loadedLiquidData->liquidHeight && ly_int >= 0 && ly_int < _loadedLiquidData->liquidWidth)
|
||||
{
|
||||
// Get water level
|
||||
float liquid_level = _loadedLiquidData->liquidMap ? _loadedLiquidData->liquidMap->at(lx_int * _loadedLiquidData->liquidWidth + ly_int) : _loadedLiquidData->liquidLevel;
|
||||
// Get ground level
|
||||
float ground_level = getHeight(x, y);
|
||||
|
||||
// Check water level and ground level (sub 0.2 for fix some errors)
|
||||
if (liquid_level >= ground_level && z >= ground_level - 0.2f)
|
||||
{
|
||||
// All ok in water -> store data
|
||||
liquidData.Entry = entry;
|
||||
liquidData.Flags = type;
|
||||
liquidData.Level = liquid_level;
|
||||
liquidData.DepthLevel = ground_level;
|
||||
|
||||
// For speed check as int values
|
||||
float delta = liquid_level - z;
|
||||
|
||||
if (delta > collisionHeight)
|
||||
liquidData.Status = LIQUID_MAP_UNDER_WATER;
|
||||
else if (delta > 0.0f)
|
||||
liquidData.Status = LIQUID_MAP_IN_WATER;
|
||||
else if (delta > -0.1f)
|
||||
liquidData.Status = LIQUID_MAP_WATER_WALK;
|
||||
else
|
||||
liquidData.Status = LIQUID_MAP_ABOVE_WATER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return liquidData;
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRID_TERRAIN_DATA_H
|
||||
#define GRID_TERRAIN_DATA_H
|
||||
|
||||
#include "Common.h"
|
||||
#include <fstream>
|
||||
#include <G3D/Plane.h>
|
||||
#include <memory>
|
||||
|
||||
#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface
|
||||
#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE
|
||||
#define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT
|
||||
#define MIN_HEIGHT -500.0f
|
||||
|
||||
#define MAP_LIQUID_STATUS_SWIMMING (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)
|
||||
#define MAP_LIQUID_STATUS_IN_CONTACT (MAP_LIQUID_STATUS_SWIMMING | LIQUID_MAP_WATER_WALK)
|
||||
|
||||
#define MAP_LIQUID_TYPE_NO_WATER 0x00
|
||||
#define MAP_LIQUID_TYPE_WATER 0x01
|
||||
#define MAP_LIQUID_TYPE_OCEAN 0x02
|
||||
#define MAP_LIQUID_TYPE_MAGMA 0x04
|
||||
#define MAP_LIQUID_TYPE_SLIME 0x08
|
||||
|
||||
#define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)
|
||||
|
||||
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
|
||||
|
||||
// ******************************************
|
||||
// Map file format defines
|
||||
// ******************************************
|
||||
union u_map_magic
|
||||
{
|
||||
char asChar[4];
|
||||
uint32 asUInt;
|
||||
};
|
||||
|
||||
const u_map_magic MapMagic = { {'M', 'A', 'P', 'S'} };
|
||||
const uint32 MapVersionMagic = 9;
|
||||
const u_map_magic MapAreaMagic = { {'A', 'R', 'E', 'A'} };
|
||||
const u_map_magic MapHeightMagic = { {'M', 'H', 'G', 'T'} };
|
||||
const u_map_magic MapLiquidMagic = { {'M', 'L', 'I', 'Q'} };
|
||||
|
||||
struct map_fileheader
|
||||
{
|
||||
uint32 mapMagic;
|
||||
uint32 versionMagic;
|
||||
uint32 buildMagic;
|
||||
uint32 areaMapOffset;
|
||||
uint32 areaMapSize;
|
||||
uint32 heightMapOffset;
|
||||
uint32 heightMapSize;
|
||||
uint32 liquidMapOffset;
|
||||
uint32 liquidMapSize;
|
||||
uint32 holesOffset;
|
||||
uint32 holesSize;
|
||||
};
|
||||
|
||||
#define MAP_AREA_NO_AREA 0x0001
|
||||
|
||||
struct map_areaHeader
|
||||
{
|
||||
uint32 fourcc;
|
||||
uint16 flags;
|
||||
uint16 gridArea;
|
||||
};
|
||||
|
||||
#define MAP_HEIGHT_NO_HEIGHT 0x0001
|
||||
#define MAP_HEIGHT_AS_INT16 0x0002
|
||||
#define MAP_HEIGHT_AS_INT8 0x0004
|
||||
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
|
||||
|
||||
struct map_heightHeader
|
||||
{
|
||||
uint32 fourcc;
|
||||
uint32 flags;
|
||||
float gridHeight;
|
||||
float gridMaxHeight;
|
||||
};
|
||||
|
||||
#define MAP_LIQUID_NO_TYPE 0x0001
|
||||
#define MAP_LIQUID_NO_HEIGHT 0x0002
|
||||
|
||||
struct map_liquidHeader
|
||||
{
|
||||
uint32 fourcc;
|
||||
uint8 flags;
|
||||
uint8 liquidFlags;
|
||||
uint16 liquidType;
|
||||
uint8 offsetX;
|
||||
uint8 offsetY;
|
||||
uint8 width;
|
||||
uint8 height;
|
||||
float liquidLevel;
|
||||
};
|
||||
|
||||
// ******************************************
|
||||
// Loaded map data structures
|
||||
// ******************************************
|
||||
|
||||
struct LoadedAreaData
|
||||
{
|
||||
typedef std::array<uint16, 16 * 16> AreaMapType;
|
||||
|
||||
uint16 gridArea;
|
||||
std::unique_ptr<AreaMapType> areaMap;
|
||||
};
|
||||
|
||||
struct LoadedHeightData
|
||||
{
|
||||
typedef std::array<G3D::Plane, 8> HeightPlanesType;
|
||||
|
||||
struct Uint16HeightData
|
||||
{
|
||||
typedef std::array<uint16, 129 * 129> V9Type;
|
||||
typedef std::array<uint16, 128 * 128> V8Type;
|
||||
|
||||
V9Type v9;
|
||||
V8Type v8;
|
||||
float gridIntHeightMultiplier;
|
||||
};
|
||||
|
||||
struct Uint8HeightData
|
||||
{
|
||||
typedef std::array<uint8, 129 * 129> V9Type;
|
||||
typedef std::array<uint8, 128 * 128> V8Type;
|
||||
|
||||
V9Type v9;
|
||||
V8Type v8;
|
||||
float gridIntHeightMultiplier;
|
||||
};
|
||||
|
||||
struct FloatHeightData
|
||||
{
|
||||
typedef std::array<float, 129 * 129> V9Type;
|
||||
typedef std::array<float, 128 * 128> V8Type;
|
||||
|
||||
V9Type v9;
|
||||
V8Type v8;
|
||||
};
|
||||
|
||||
float gridHeight;
|
||||
std::unique_ptr<Uint16HeightData> uint16HeightData;
|
||||
std::unique_ptr<Uint8HeightData> uint8HeightData;
|
||||
std::unique_ptr<FloatHeightData> floatHeightData;
|
||||
std::unique_ptr<HeightPlanesType> minHeightPlanes;
|
||||
};
|
||||
|
||||
struct LoadedLiquidData
|
||||
{
|
||||
typedef std::array<uint16, 16 * 16> LiquidEntryType;
|
||||
typedef std::array<uint8, 16 * 16> LiquidFlagsType;
|
||||
typedef std::vector<float> LiquidMapType;
|
||||
|
||||
uint16 liquidGlobalEntry;
|
||||
uint8 liquidGlobalFlags;
|
||||
uint8 liquidOffX;
|
||||
uint8 liquidOffY;
|
||||
uint8 liquidWidth;
|
||||
uint8 liquidHeight;
|
||||
float liquidLevel;
|
||||
std::unique_ptr<LiquidEntryType> liquidEntry;
|
||||
std::unique_ptr<LiquidFlagsType> liquidFlags;
|
||||
std::unique_ptr<LiquidMapType> liquidMap;
|
||||
};
|
||||
|
||||
struct LoadedHoleData
|
||||
{
|
||||
typedef std::array<uint16, 16 * 16> HolesType;
|
||||
|
||||
HolesType holes;
|
||||
};
|
||||
|
||||
enum LiquidStatus
|
||||
{
|
||||
LIQUID_MAP_NO_WATER = 0x00000000,
|
||||
LIQUID_MAP_ABOVE_WATER = 0x00000001,
|
||||
LIQUID_MAP_WATER_WALK = 0x00000002,
|
||||
LIQUID_MAP_IN_WATER = 0x00000004,
|
||||
LIQUID_MAP_UNDER_WATER = 0x00000008
|
||||
};
|
||||
|
||||
struct LiquidData
|
||||
{
|
||||
LiquidData() = default;
|
||||
|
||||
uint32 Entry{ 0 };
|
||||
uint32 Flags{ 0 };
|
||||
float Level{ INVALID_HEIGHT };
|
||||
float DepthLevel{ INVALID_HEIGHT };
|
||||
LiquidStatus Status{ LIQUID_MAP_NO_WATER };
|
||||
};
|
||||
|
||||
enum class TerrainMapDataReadResult
|
||||
{
|
||||
Success,
|
||||
NotFound,
|
||||
ReadError,
|
||||
InvalidMagic,
|
||||
InvalidAreaData,
|
||||
InvalidHeightData,
|
||||
InvalidLiquidData,
|
||||
InvalidHoleData
|
||||
};
|
||||
|
||||
class GridTerrainData
|
||||
{
|
||||
bool LoadAreaData(std::ifstream& fileStream, uint32 const offset);
|
||||
bool LoadHeightData(std::ifstream& fileStream, uint32 const offset);
|
||||
bool LoadLiquidData(std::ifstream& fileStream, uint32 const offset);
|
||||
bool LoadHolesData(std::ifstream& fileStream, uint32 const offset);
|
||||
|
||||
std::unique_ptr<LoadedAreaData> _loadedAreaData;
|
||||
std::unique_ptr<LoadedHeightData> _loadedHeightData;
|
||||
std::unique_ptr<LoadedLiquidData> _loadedLiquidData;
|
||||
std::unique_ptr<LoadedHoleData> _loadedHoleData;
|
||||
|
||||
bool isHole(int row, int col) const;
|
||||
|
||||
// Get height functions and pointers
|
||||
typedef float (GridTerrainData::* GetHeightPtr) (float x, float y) const;
|
||||
GetHeightPtr _gridGetHeight;
|
||||
float getHeightFromFloat(float x, float y) const;
|
||||
float getHeightFromUint16(float x, float y) const;
|
||||
float getHeightFromUint8(float x, float y) const;
|
||||
float getHeightFromFlat(float x, float y) const;
|
||||
|
||||
public:
|
||||
GridTerrainData();
|
||||
~GridTerrainData() { };
|
||||
TerrainMapDataReadResult Load(std::string const& mapFileName);
|
||||
|
||||
uint16 getArea(float x, float y) const;
|
||||
inline float getHeight(float x, float y) const { return (this->*_gridGetHeight)(x, y); }
|
||||
float getMinHeight(float x, float y) const;
|
||||
float getLiquidLevel(float x, float y) const;
|
||||
LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,157 @@
|
||||
#include "DisableMgr.h"
|
||||
#include "GridTerrainLoader.h"
|
||||
#include "MMapFactory.h"
|
||||
#include "MMapMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "VMapMgr2.h"
|
||||
|
||||
void GridTerrainLoader::LoadTerrain()
|
||||
{
|
||||
LoadMap();
|
||||
if (_map->GetInstanceId() == 0)
|
||||
{
|
||||
LoadVMap();
|
||||
LoadMMap();
|
||||
}
|
||||
}
|
||||
|
||||
void GridTerrainLoader::LoadMap()
|
||||
{
|
||||
// Instances will point to the parent maps terrain data
|
||||
if (_map->GetInstanceId() != 0)
|
||||
{
|
||||
// load grid map for base map
|
||||
Map* parentMap = const_cast<Map*>(_map->GetParent());
|
||||
|
||||
// GetGridTerrainData will create the parent map grid
|
||||
_grid.SetTerrainData(parentMap->GetGridTerrainDataSharedPtr(GridCoord(_grid.GetX(), _grid.GetY())));
|
||||
return;
|
||||
}
|
||||
|
||||
// map file name
|
||||
std::string const mapFileName = Acore::StringFormat("{}maps/{:03}{:02}{:02}.map", sWorld->GetDataPath(), _map->GetId(), _grid.GetX(), _grid.GetY());
|
||||
|
||||
// loading data
|
||||
LOG_DEBUG("maps", "Loading map {}", mapFileName);
|
||||
std::unique_ptr<GridTerrainData> terrainData = std::make_unique<GridTerrainData>();
|
||||
TerrainMapDataReadResult loadResult = terrainData->Load(mapFileName);
|
||||
if (loadResult == TerrainMapDataReadResult::Success)
|
||||
_grid.SetTerrainData(std::move(terrainData));
|
||||
else
|
||||
{
|
||||
if (loadResult == TerrainMapDataReadResult::InvalidMagic)
|
||||
LOG_ERROR("maps", "Map file '{}' is from an incompatible clientversion. Please recreate using the mapextractor.", mapFileName);
|
||||
else
|
||||
LOG_DEBUG("maps", "Error (result: {}) loading map file: {}", uint32(loadResult), mapFileName);
|
||||
}
|
||||
|
||||
sScriptMgr->OnLoadGridMap(_map, _grid.GetTerrainData(), _grid.GetX(), _grid.GetY());
|
||||
}
|
||||
|
||||
void GridTerrainLoader::LoadVMap()
|
||||
{
|
||||
int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapMgr()->loadMap((sWorld->GetDataPath() + "vmaps").c_str(), _map->GetId(), _grid.GetX(), _grid.GetY());
|
||||
switch (vmapLoadResult)
|
||||
{
|
||||
case VMAP::VMAP_LOAD_RESULT_OK:
|
||||
LOG_DEBUG("maps", "VMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
|
||||
_map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY());
|
||||
break;
|
||||
case VMAP::VMAP_LOAD_RESULT_ERROR:
|
||||
LOG_DEBUG("maps", "Could not load VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
|
||||
_map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY());
|
||||
break;
|
||||
case VMAP::VMAP_LOAD_RESULT_IGNORED:
|
||||
LOG_DEBUG("maps", "Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
|
||||
_map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GridTerrainLoader::LoadMMap()
|
||||
{
|
||||
if (!DisableMgr::IsPathfindingEnabled(_map))
|
||||
return;
|
||||
|
||||
int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(_map->GetId(), _grid.GetX(), _grid.GetY());
|
||||
switch (mmapLoadResult)
|
||||
{
|
||||
case MMAP::MMAP_LOAD_RESULT_OK:
|
||||
LOG_DEBUG("maps", "MMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
|
||||
_map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY());
|
||||
break;
|
||||
case MMAP::MMAP_LOAD_RESULT_ERROR:
|
||||
LOG_DEBUG("maps", "Could not load MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
|
||||
_map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY());
|
||||
break;
|
||||
case MMAP::MMAP_LOAD_RESULT_IGNORED:
|
||||
LOG_DEBUG("maps", "Ignored MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
|
||||
_map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool GridTerrainLoader::ExistMap(uint32 mapid, int gx, int gy)
|
||||
{
|
||||
std::string const mapFileName = Acore::StringFormat("{}maps/{:03}{:02}{:02}.map", sWorld->GetDataPath(), mapid, gx, gy);
|
||||
std::ifstream fileStream(mapFileName, std::ios::binary);
|
||||
if (fileStream.fail())
|
||||
{
|
||||
LOG_DEBUG("maps", "Map file '{}': error opening file", mapFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
map_fileheader header;
|
||||
if (!fileStream.read(reinterpret_cast<char*>(&header), sizeof(header)))
|
||||
{
|
||||
LOG_DEBUG("maps", "Map file '{}': unable to read header", mapFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.mapMagic != MapMagic.asUInt || header.versionMagic != MapVersionMagic)
|
||||
{
|
||||
LOG_ERROR("maps", "Map file '{}' is from an incompatible map version ({:.4u} v{}), {:.4s} v{} is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files.",
|
||||
mapFileName, 4, header.mapMagic, header.versionMagic, 4, MapMagic.asChar, MapVersionMagic);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GridTerrainLoader::ExistVMap(uint32 mapid, int gx, int gy)
|
||||
{
|
||||
if (VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr())
|
||||
{
|
||||
if (vmgr->isMapLoadingEnabled())
|
||||
{
|
||||
VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), mapid, gx, gy);
|
||||
std::string name = vmgr->getDirFileName(mapid, gx, gy);
|
||||
switch (result)
|
||||
{
|
||||
case VMAP::LoadResult::Success:
|
||||
break;
|
||||
case VMAP::LoadResult::FileNotFound:
|
||||
LOG_DEBUG("maps", "VMap file '{}' does not exist", (sWorld->GetDataPath() + "vmaps/" + name));
|
||||
LOG_DEBUG("maps", "Please place VMAP files (*.vmtree and *.vmtile) in the vmap directory ({}), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath() + "vmaps/"));
|
||||
return false;
|
||||
case VMAP::LoadResult::VersionMismatch:
|
||||
LOG_ERROR("maps", "VMap file '{}' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name));
|
||||
LOG_ERROR("maps", "This is because the version of the VMap file and the version of this module are different, please re-extract the maps with the tools compiled with this module.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GridTerrainUnloader::UnloadTerrain()
|
||||
{
|
||||
// Only parent maps manage terrain data
|
||||
if (_map->GetInstanceId() != 0)
|
||||
return;
|
||||
|
||||
VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(_map->GetId(), _grid.GetX(), _grid.GetY());
|
||||
MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(_map->GetId(), _grid.GetX(), _grid.GetY());
|
||||
}
|
||||
+37
-8
@@ -15,13 +15,42 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptMgrMacros.h"
|
||||
#ifndef ACORE_GRID_TERRAIN_LOADER_H
|
||||
#define ACORE_GRID_TERRAIN_LOADER_H
|
||||
|
||||
void ScriptMgr::OnMetricLogging()
|
||||
#include "GridDefines.h"
|
||||
|
||||
class GridTerrainLoader
|
||||
{
|
||||
ExecuteScript<MetricScript>([&](MetricScript* script)
|
||||
{
|
||||
script->OnMetricLogging();
|
||||
});
|
||||
}
|
||||
public:
|
||||
GridTerrainLoader(MapGridType& grid, Map* map)
|
||||
: _grid(grid), _map(map) { }
|
||||
|
||||
void LoadTerrain();
|
||||
|
||||
static bool ExistMap(uint32 mapid, int gx, int gy);
|
||||
static bool ExistVMap(uint32 mapid, int gx, int gy);
|
||||
|
||||
private:
|
||||
void LoadMap();
|
||||
void LoadVMap();
|
||||
void LoadMMap();
|
||||
|
||||
MapGridType& _grid;
|
||||
Map* _map;
|
||||
};
|
||||
|
||||
class GridTerrainUnloader
|
||||
{
|
||||
public:
|
||||
GridTerrainUnloader(MapGridType& grid, Map* map)
|
||||
: _grid(grid), _map(map) { }
|
||||
|
||||
void UnloadTerrain();
|
||||
|
||||
private:
|
||||
MapGridType& _grid;
|
||||
Map* _map;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MAP_GRID_H
|
||||
#define MAP_GRID_H
|
||||
|
||||
#include "GridCell.h"
|
||||
#include "GridReference.h"
|
||||
|
||||
class GridTerrainData;
|
||||
|
||||
template
|
||||
<
|
||||
class WORLD_OBJECT_TYPES,
|
||||
class GRID_OBJECT_TYPES
|
||||
>
|
||||
class MapGrid
|
||||
{
|
||||
public:
|
||||
typedef GridCell<WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> GridCellType;
|
||||
|
||||
MapGrid(uint16 const x, uint16 const y)
|
||||
: _x(x), _y(y), _objectDataLoaded(false), _terrainData(nullptr) { }
|
||||
|
||||
// Unique identifier for grid
|
||||
uint32 GetId() const { return _y * MAX_NUMBER_OF_GRIDS + _x; }
|
||||
|
||||
uint16 GetX() const { return _x; }
|
||||
uint16 GetY() const { return _y; }
|
||||
|
||||
bool IsObjectDataLoaded() const { return _objectDataLoaded; }
|
||||
void SetObjectDataLoaded() { _objectDataLoaded = true; }
|
||||
|
||||
template<class SPECIFIC_OBJECT> void AddWorldObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
GetOrCreateCell(x, y).AddWorldObject(obj);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT> void RemoveWorldObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
GetOrCreateCell(x, y).RemoveWorldObject(obj);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT> void AddGridObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
GetOrCreateCell(x, y).AddGridObject(obj);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT> void RemoveGridObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
GetOrCreateCell(x, y).RemoveGridObject(obj);
|
||||
}
|
||||
|
||||
// Visit all cells
|
||||
template<class T, class TT>
|
||||
void VisitAllCells(TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
|
||||
{
|
||||
for (auto& cellX : _cells)
|
||||
{
|
||||
for (auto& cellY : cellX)
|
||||
{
|
||||
if (!cellY)
|
||||
continue;
|
||||
|
||||
cellY->Visit(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Visit single cell
|
||||
template<class T, class TT>
|
||||
void VisitCell(uint16 const x, uint16 const y, TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
|
||||
{
|
||||
GridCellType* gridCell = GetCell(x, y);
|
||||
if (!gridCell)
|
||||
return;
|
||||
|
||||
gridCell->Visit(visitor);
|
||||
}
|
||||
|
||||
void link(GridRefMgr<MapGrid<WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES>>* pTo)
|
||||
{
|
||||
_gridReference.link(pTo, this);
|
||||
}
|
||||
|
||||
GridTerrainData* GetTerrainData() const { return _terrainData.get(); }
|
||||
std::shared_ptr<GridTerrainData> GetTerrainDataSharedPtr() { return _terrainData; }
|
||||
void SetTerrainData(std::shared_ptr<GridTerrainData> terrainData) { _terrainData = terrainData; }
|
||||
|
||||
uint32 GetCreatedCellsCount()
|
||||
{
|
||||
uint32 count = 0;
|
||||
for (auto& cellX : _cells)
|
||||
{
|
||||
for (auto& cellY : cellX)
|
||||
{
|
||||
if (!cellY)
|
||||
continue;
|
||||
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
// Creates and returns the cell if not already created
|
||||
GridCellType& GetOrCreateCell(uint16 const x, uint16 const y)
|
||||
{
|
||||
GridCellType* cell = GetCell(x, y);
|
||||
if (!cell)
|
||||
_cells[x][y] = std::make_unique<GridCellType>();
|
||||
|
||||
return *_cells[x][y];
|
||||
}
|
||||
|
||||
GridCellType* GetCell(uint16 const x, uint16 const y)
|
||||
{
|
||||
ASSERT(x < MAX_NUMBER_OF_CELLS && y < MAX_NUMBER_OF_CELLS);
|
||||
return _cells[x][y].get();
|
||||
}
|
||||
|
||||
GridCellType const* GetCell(uint16 const x, uint16 const y) const
|
||||
{
|
||||
ASSERT(x < MAX_NUMBER_OF_CELLS && y < MAX_NUMBER_OF_CELLS);
|
||||
return _cells[x][y].get();
|
||||
}
|
||||
|
||||
uint16 _x;
|
||||
uint16 _y;
|
||||
|
||||
bool _objectDataLoaded;
|
||||
std::array<std::array<std::unique_ptr<GridCellType>, MAX_NUMBER_OF_CELLS>, MAX_NUMBER_OF_CELLS> _cells; // N * N array
|
||||
GridReference<MapGrid<WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES>> _gridReference;
|
||||
|
||||
// Instances will share a copy of the parent maps terrainData
|
||||
std::shared_ptr<GridTerrainData> _terrainData;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
#include "MapGridManager.h"
|
||||
#include "GridObjectLoader.h"
|
||||
#include "GridTerrainLoader.h"
|
||||
|
||||
void MapGridManager::CreateGrid(uint16 const x, uint16 const y)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_gridLock);
|
||||
if (IsGridCreated(x, y))
|
||||
return;
|
||||
|
||||
std::unique_ptr<MapGridType> grid = std::make_unique<MapGridType>(x, y);
|
||||
grid->link(_map);
|
||||
|
||||
GridTerrainLoader loader(*grid, _map);
|
||||
loader.LoadTerrain();
|
||||
|
||||
_mapGrid[x][y] = std::move(grid);
|
||||
|
||||
++_createdGridsCount;
|
||||
}
|
||||
|
||||
bool MapGridManager::LoadGrid(uint16 const x, uint16 const y)
|
||||
{
|
||||
MapGridType* grid = GetGrid(x, y);
|
||||
if (!grid || grid->IsObjectDataLoaded())
|
||||
return false;
|
||||
|
||||
// Must mark as loaded first, as GridObjectLoader spawning objects can attempt to recursively load the grid
|
||||
grid->SetObjectDataLoaded();
|
||||
|
||||
GridObjectLoader loader(*grid, _map);
|
||||
loader.LoadAllCellsInGrid();
|
||||
|
||||
++_loadedGridsCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MapGridManager::UnloadGrid(uint16 const x, uint16 const y)
|
||||
{
|
||||
MapGridType* grid = GetGrid(x, y);
|
||||
if (!grid)
|
||||
return;
|
||||
|
||||
{
|
||||
GridObjectCleaner worker;
|
||||
TypeContainerVisitor<GridObjectCleaner, GridTypeMapContainer> visitor(worker);
|
||||
grid->VisitAllCells(visitor);
|
||||
}
|
||||
|
||||
_map->RemoveAllObjectsInRemoveList();
|
||||
|
||||
{
|
||||
GridObjectUnloader worker;
|
||||
TypeContainerVisitor<GridObjectUnloader, GridTypeMapContainer> visitor(worker);
|
||||
grid->VisitAllCells(visitor);
|
||||
}
|
||||
|
||||
GridTerrainUnloader terrainUnloader(*grid, _map);
|
||||
terrainUnloader.UnloadTerrain();
|
||||
|
||||
_mapGrid[x][y] = nullptr;
|
||||
}
|
||||
|
||||
bool MapGridManager::IsGridCreated(uint16 const x, uint16 const y) const
|
||||
{
|
||||
if (!MapGridManager::IsValidGridCoordinates(x, y))
|
||||
return false;
|
||||
|
||||
return _mapGrid[x][y].get();
|
||||
}
|
||||
|
||||
bool MapGridManager::IsGridLoaded(uint16 const x, uint16 const y) const
|
||||
{
|
||||
if (!MapGridManager::IsValidGridCoordinates(x, y))
|
||||
return false;
|
||||
|
||||
return _mapGrid[x][y].get() && _mapGrid[x][y]->IsObjectDataLoaded();
|
||||
}
|
||||
|
||||
MapGridType* MapGridManager::GetGrid(uint16 const x, uint16 const y)
|
||||
{
|
||||
if (!MapGridManager::IsValidGridCoordinates(x, y))
|
||||
return nullptr;
|
||||
|
||||
return _mapGrid[x][y].get();
|
||||
}
|
||||
|
||||
uint32 MapGridManager::GetCreatedGridsCount()
|
||||
{
|
||||
return _createdGridsCount;
|
||||
}
|
||||
|
||||
uint32 MapGridManager::GetLoadedGridsCount()
|
||||
{
|
||||
return _loadedGridsCount;
|
||||
}
|
||||
|
||||
uint32 MapGridManager::GetCreatedCellsInGridCount(uint16 const x, uint16 const y)
|
||||
{
|
||||
MapGridType* grid = GetGrid(x, y);
|
||||
if (grid)
|
||||
return grid->GetCreatedCellsCount();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 MapGridManager::GetCreatedCellsInMapCount()
|
||||
{
|
||||
uint32 count = 0;
|
||||
for (uint32 gridX = 0; gridX < MAX_NUMBER_OF_GRIDS; ++gridX)
|
||||
{
|
||||
for (uint32 gridY = 0; gridY < MAX_NUMBER_OF_GRIDS; ++gridY)
|
||||
{
|
||||
if (MapGridType* grid = GetGrid(gridX, gridY))
|
||||
count += grid->GetCreatedCellsCount();
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool MapGridManager::IsGridsFullyCreated() const
|
||||
{
|
||||
return _createdGridsCount == (MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS);
|
||||
}
|
||||
|
||||
bool MapGridManager::IsGridsFullyLoaded() const
|
||||
{
|
||||
return _loadedGridsCount == (MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MAP_GRID_MANAGER_H
|
||||
#define MAP_GRID_MANAGER_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "GridDefines.h"
|
||||
#include "MapDefines.h"
|
||||
#include "MapGrid.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
class Map;
|
||||
|
||||
class MapGridManager
|
||||
{
|
||||
public:
|
||||
MapGridManager(Map* map) : _map(map), _createdGridsCount(0), _loadedGridsCount(0) { }
|
||||
|
||||
void CreateGrid(uint16 const x, uint16 const y);
|
||||
bool LoadGrid(uint16 const x, uint16 const y);
|
||||
void UnloadGrid(uint16 const x, uint16 const y);
|
||||
bool IsGridCreated(uint16 const x, uint16 const y) const;
|
||||
bool IsGridLoaded(uint16 const x, uint16 const y) const;
|
||||
MapGridType* GetGrid(uint16 const x, uint16 const y);
|
||||
|
||||
static bool IsValidGridCoordinates(uint16 const x, uint16 const y) { return (x < MAX_NUMBER_OF_GRIDS && y < MAX_NUMBER_OF_GRIDS); }
|
||||
|
||||
uint32 GetCreatedGridsCount();
|
||||
uint32 GetLoadedGridsCount();
|
||||
uint32 GetCreatedCellsInGridCount(uint16 const x, uint16 const y);
|
||||
uint32 GetCreatedCellsInMapCount();
|
||||
|
||||
bool IsGridsFullyCreated() const;
|
||||
bool IsGridsFullyLoaded() const;
|
||||
|
||||
private:
|
||||
Map* _map;
|
||||
|
||||
uint32 _createdGridsCount;
|
||||
uint32 _loadedGridsCount;
|
||||
|
||||
std::mutex _gridLock;
|
||||
std::unique_ptr<MapGridType> _mapGrid[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACORE_NGRID_H
|
||||
#define ACORE_NGRID_H
|
||||
|
||||
/** NGrid is nothing more than a wrapper of the Grid with an NxN cells
|
||||
*/
|
||||
|
||||
#include "Grid.h"
|
||||
#include "GridReference.h"
|
||||
#include "Timer.h"
|
||||
|
||||
template
|
||||
<
|
||||
uint32 N,
|
||||
class ACTIVE_OBJECT,
|
||||
class WORLD_OBJECT_TYPES,
|
||||
class GRID_OBJECT_TYPES
|
||||
>
|
||||
class NGrid
|
||||
{
|
||||
public:
|
||||
typedef Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> GridType;
|
||||
NGrid(uint32 id, int32 x, int32 y)
|
||||
: i_gridId(id), i_x(x), i_y(y), i_GridObjectDataLoaded(false)
|
||||
{
|
||||
}
|
||||
|
||||
GridType& GetGridType(const uint32 x, const uint32 y)
|
||||
{
|
||||
ASSERT(x < N && y < N);
|
||||
return i_cells[x][y];
|
||||
}
|
||||
|
||||
[[nodiscard]] GridType const& GetGridType(const uint32 x, const uint32 y) const
|
||||
{
|
||||
ASSERT(x < N && y < N);
|
||||
return i_cells[x][y];
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32 GetGridId() const { return i_gridId; }
|
||||
[[nodiscard]] int32 getX() const { return i_x; }
|
||||
[[nodiscard]] int32 getY() const { return i_y; }
|
||||
|
||||
void link(GridRefMgr<NGrid<N, ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> >* pTo)
|
||||
{
|
||||
i_Reference.link(pTo, this);
|
||||
}
|
||||
[[nodiscard]] bool isGridObjectDataLoaded() const { return i_GridObjectDataLoaded; }
|
||||
void setGridObjectDataLoaded(bool pLoaded) { i_GridObjectDataLoaded = pLoaded; }
|
||||
|
||||
/*
|
||||
template<class SPECIFIC_OBJECT> void AddWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
|
||||
{
|
||||
GetGridType(x, y).AddWorldObject(obj);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT> void RemoveWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
|
||||
{
|
||||
GetGridType(x, y).RemoveWorldObject(obj);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT> void AddGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
|
||||
{
|
||||
GetGridType(x, y).AddGridObject(obj);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT> void RemoveGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
|
||||
{
|
||||
GetGridType(x, y).RemoveGridObject(obj);
|
||||
}
|
||||
*/
|
||||
|
||||
// Visit all Grids (cells) in NGrid (grid)
|
||||
template<class T, class TT>
|
||||
void VisitAllGrids(TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
|
||||
{
|
||||
for (uint32 x = 0; x < N; ++x)
|
||||
for (uint32 y = 0; y < N; ++y)
|
||||
GetGridType(x, y).Visit(visitor);
|
||||
}
|
||||
|
||||
// Visit a single Grid (cell) in NGrid (grid)
|
||||
template<class T, class TT>
|
||||
void VisitGrid(const uint32 x, const uint32 y, TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
|
||||
{
|
||||
GetGridType(x, y).Visit(visitor);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 i_gridId;
|
||||
GridReference<NGrid<N, ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> > i_Reference;
|
||||
int32 i_x;
|
||||
int32 i_y;
|
||||
GridType i_cells[N][N];
|
||||
bool i_GridObjectDataLoaded;
|
||||
};
|
||||
#endif
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "GameObject.h"
|
||||
#include "Group.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectGridLoader.h"
|
||||
#include "GridObjectLoader.h"
|
||||
#include "Optional.h"
|
||||
#include "Player.h"
|
||||
#include "Spell.h"
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ObjectGridLoader.h"
|
||||
#include "CellImpl.h"
|
||||
#include "Corpse.h"
|
||||
#include "Creature.h"
|
||||
#include "DynamicObject.h"
|
||||
#include "GameObject.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Transport.h"
|
||||
|
||||
// for loading world object at grid loading (Corpses)
|
||||
//TODO: to implement npc on transport, also need to load npcs at grid loading
|
||||
class ObjectWorldLoader
|
||||
{
|
||||
public:
|
||||
explicit ObjectWorldLoader(ObjectGridLoader& gloader)
|
||||
: i_cell(gloader.i_cell), i_map(gloader.i_map), i_grid(gloader.i_grid), i_corpses(gloader.i_corpses)
|
||||
{}
|
||||
|
||||
void Visit(CorpseMapType& m);
|
||||
|
||||
template<class T> void Visit(GridRefMgr<T>&) { }
|
||||
|
||||
private:
|
||||
Cell i_cell;
|
||||
Map* i_map;
|
||||
NGridType& i_grid;
|
||||
public:
|
||||
uint32& i_corpses;
|
||||
};
|
||||
|
||||
template<class T> void ObjectGridLoader::SetObjectCell(T* /*obj*/, CellCoord const& /*cellCoord*/)
|
||||
{
|
||||
}
|
||||
|
||||
template<> void ObjectGridLoader::SetObjectCell(Creature* obj, CellCoord const& cellCoord)
|
||||
{
|
||||
Cell cell(cellCoord);
|
||||
obj->SetCurrentCell(cell);
|
||||
}
|
||||
|
||||
template<> void ObjectGridLoader::SetObjectCell(GameObject* obj, CellCoord const& cellCoord)
|
||||
{
|
||||
Cell cell(cellCoord);
|
||||
obj->SetCurrentCell(cell);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AddObjectHelper(CellCoord& cell, GridRefMgr<T>& m, uint32& count, Map* /*map*/, T* obj)
|
||||
{
|
||||
obj->AddToGrid(m);
|
||||
ObjectGridLoader::SetObjectCell(obj, cell);
|
||||
obj->AddToWorld();
|
||||
++count;
|
||||
}
|
||||
|
||||
template <>
|
||||
void AddObjectHelper(CellCoord& cell, CreatureMapType& m, uint32& count, Map* map, Creature* obj)
|
||||
{
|
||||
obj->AddToGrid(m);
|
||||
ObjectGridLoader::SetObjectCell(obj, cell);
|
||||
obj->AddToWorld();
|
||||
if (obj->isActiveObject())
|
||||
map->AddToActive(obj);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
template <>
|
||||
void AddObjectHelper(CellCoord& cell, GameObjectMapType& m, uint32& count, Map* map, GameObject* obj)
|
||||
{
|
||||
obj->AddToGrid(m);
|
||||
ObjectGridLoader::SetObjectCell(obj, cell);
|
||||
obj->AddToWorld();
|
||||
if (obj->isActiveObject())
|
||||
map->AddToActive(obj);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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)
|
||||
{
|
||||
Creature* obj = new Creature();
|
||||
ObjectGuid::LowType guid = *i_guid;
|
||||
if (!obj->LoadFromDB(guid, map))
|
||||
{
|
||||
delete obj;
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgr<GameObject>& m, uint32& count, Map* map)
|
||||
{
|
||||
for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid)
|
||||
{
|
||||
ObjectGuid::LowType guid = *i_guid;
|
||||
GameObjectData const* data = sObjectMgr->GetGameObjectData(guid);
|
||||
GameObject* obj = data && sObjectMgr->IsGameObjectStaticTransport(data->id) ? new StaticTransport() : new GameObject();
|
||||
|
||||
if (!obj->LoadFromDB(guid, map))
|
||||
{
|
||||
delete obj;
|
||||
continue;
|
||||
}
|
||||
|
||||
AddObjectHelper(cell, m, count, map, obj);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGridLoader::Visit(GameObjectMapType& m)
|
||||
{
|
||||
CellCoord cellCoord = i_cell.GetCellCoord();
|
||||
CellObjectGuids const& cell_guids = sObjectMgr->GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cellCoord.GetId());
|
||||
LoadHelper(cell_guids.gameobjects, cellCoord, m, i_gameObjects, i_map);
|
||||
}
|
||||
|
||||
void ObjectGridLoader::Visit(CreatureMapType& m)
|
||||
{
|
||||
CellCoord cellCoord = i_cell.GetCellCoord();
|
||||
CellObjectGuids const& cell_guids = sObjectMgr->GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cellCoord.GetId());
|
||||
LoadHelper(cell_guids.creatures, cellCoord, m, i_creatures, i_map);
|
||||
}
|
||||
|
||||
void ObjectWorldLoader::Visit(CorpseMapType& /*m*/)
|
||||
{
|
||||
CellCoord cellCoord = i_cell.GetCellCoord();
|
||||
if (std::unordered_set<Corpse*> const* corpses = i_map->GetCorpsesInCell(cellCoord.GetId()))
|
||||
{
|
||||
for (Corpse* corpse : *corpses)
|
||||
{
|
||||
corpse->AddToWorld();
|
||||
GridType& cell = i_grid.GetGridType(i_cell.CellX(), i_cell.CellY());
|
||||
if (corpse->IsWorldObject())
|
||||
cell.AddWorldObject(corpse);
|
||||
else
|
||||
cell.AddGridObject(corpse);
|
||||
|
||||
++i_corpses;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGridLoader::LoadN(void)
|
||||
{
|
||||
i_gameObjects = 0;
|
||||
i_creatures = 0;
|
||||
i_corpses = 0;
|
||||
i_cell.data.Part.cell_y = 0;
|
||||
for (uint32 x = 0; x < MAX_NUMBER_OF_CELLS; ++x)
|
||||
{
|
||||
i_cell.data.Part.cell_x = x;
|
||||
for (uint32 y = 0; y < MAX_NUMBER_OF_CELLS; ++y)
|
||||
{
|
||||
i_cell.data.Part.cell_y = y;
|
||||
|
||||
//Load creatures and game objects
|
||||
{
|
||||
TypeContainerVisitor<ObjectGridLoader, GridTypeMapContainer> visitor(*this);
|
||||
i_grid.VisitGrid(x, y, visitor);
|
||||
}
|
||||
|
||||
//Load corpses (not bones)
|
||||
{
|
||||
ObjectWorldLoader worker(*this);
|
||||
TypeContainerVisitor<ObjectWorldLoader, WorldTypeMapContainer> visitor(worker);
|
||||
i_grid.VisitGrid(x, y, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("maps", "{} GameObjects, {} Creatures, and {} Corpses/Bones loaded for grid {} on map {}", i_gameObjects, i_creatures, i_corpses, i_grid.GetGridId(), i_map->GetId());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ObjectGridUnloader::Visit(GridRefMgr<T>& m)
|
||||
{
|
||||
while (!m.IsEmpty())
|
||||
{
|
||||
T* obj = m.getFirst()->GetSource();
|
||||
// if option set then object already saved at this moment
|
||||
//if (!sWorld->getBoolConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY))
|
||||
// obj->SaveRespawnTime();
|
||||
//Some creatures may summon other temp summons in CleanupsBeforeDelete()
|
||||
//So we need this even after cleaner (maybe we can remove cleaner)
|
||||
//Example: Flame Leviathan Turret 33139 is summoned when a creature is deleted
|
||||
//TODO: Check if that script has the correct logic. Do we really need to summons something before deleting?
|
||||
obj->CleanupsBeforeDelete();
|
||||
///- object will get delinked from the manager when deleted
|
||||
delete obj;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ObjectGridCleaner::Visit(GridRefMgr<T>& m)
|
||||
{
|
||||
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
iter->GetSource()->CleanupsBeforeDelete();
|
||||
}
|
||||
|
||||
template void ObjectGridUnloader::Visit(CreatureMapType&);
|
||||
template void ObjectGridUnloader::Visit(GameObjectMapType&);
|
||||
template void ObjectGridUnloader::Visit(DynamicObjectMapType&);
|
||||
|
||||
template void ObjectGridCleaner::Visit(CreatureMapType&);
|
||||
template void ObjectGridCleaner::Visit<GameObject>(GameObjectMapType&);
|
||||
template void ObjectGridCleaner::Visit<DynamicObject>(DynamicObjectMapType&);
|
||||
template void ObjectGridCleaner::Visit<Corpse>(CorpseMapType&);
|
||||
@@ -1478,7 +1478,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
|
||||
AllowedLooterSet looters = item->GetAllowedLooters();
|
||||
Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters);
|
||||
if (_item)
|
||||
sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), NEED, roll);
|
||||
sScriptMgr->OnPlayerGroupRollRewardItem(player, _item, _item->GetCount(), NEED, roll);
|
||||
player->UpdateLootAchievements(item, roll->getLoot());
|
||||
}
|
||||
else
|
||||
@@ -1548,7 +1548,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
|
||||
AllowedLooterSet looters = item->GetAllowedLooters();
|
||||
Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters);
|
||||
if (_item)
|
||||
sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), GREED, roll);
|
||||
sScriptMgr->OnPlayerGroupRollRewardItem(player, _item, _item->GetCount(), GREED, roll);
|
||||
player->UpdateLootAchievements(item, roll->getLoot());
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1585,11 +1585,14 @@ void Guild::HandleRemoveMember(WorldSession* session, std::string_view name)
|
||||
SendCommandResult(session, GUILD_COMMAND_REMOVE, ERR_GUILD_RANK_TOO_HIGH_S, name);
|
||||
else
|
||||
{
|
||||
// Copy values since everything will be deleted in DeleteMember().
|
||||
ObjectGuid guid = member->GetGUID();
|
||||
std::string memberName = member->GetName();
|
||||
|
||||
// After call to DeleteMember pointer to member becomes invalid
|
||||
DeleteMember(guid, false, true);
|
||||
_LogEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, player->GetGUID(), guid);
|
||||
_BroadcastEvent(GE_REMOVED, ObjectGuid::Empty, member->GetName(), player->GetName());
|
||||
_BroadcastEvent(GE_REMOVED, ObjectGuid::Empty, memberName, player->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData)
|
||||
AuctionEntry* auction = auctionHouse->GetAuction(auctionId);
|
||||
Player* player = GetPlayer();
|
||||
|
||||
if (!sScriptMgr->CanPlaceAuctionBid(player, auction))
|
||||
if (!sScriptMgr->OnPlayerCanPlaceAuctionBid(player, auction))
|
||||
{
|
||||
SendAuctionCommandResult(0, AUCTION_PLACE_BID, ERR_AUCTION_RESTRICTED_ACCOUNT);
|
||||
return;
|
||||
|
||||
@@ -26,7 +26,12 @@ void WorldSession::SendAuthResponse(uint8 code, bool shortForm, uint32 queuePos)
|
||||
packet << uint32(0); // BillingTimeRemaining
|
||||
packet << uint8(0); // BillingPlanFlags
|
||||
packet << uint32(0); // BillingTimeRested
|
||||
packet << uint8(Expansion()); // 0 - normal, 1 - TBC, 2 - WOTLK, must be set in database manually for each account
|
||||
uint8 exp = Expansion(); // 0 - normal, 1 - TBC, 2 - WOTLK, must be set in database manually for each account
|
||||
|
||||
if (exp >= MAX_EXPANSIONS)
|
||||
exp = MAX_EXPANSIONS - 1;
|
||||
|
||||
packet << uint8(exp);
|
||||
|
||||
if (!shortForm)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "ArenaTeam.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "ArenaSeasonMgr.h"
|
||||
#include "Battleground.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "Chat.h"
|
||||
@@ -139,7 +140,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
|
||||
// queue result (default ok)
|
||||
GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult(bg->GetBgTypeID());
|
||||
|
||||
if (!sScriptMgr->CanJoinInBattlegroundQueue(_player, guid, bgTypeId, joinAsGroup, err) && err <= 0)
|
||||
if (!sScriptMgr->OnPlayerCanJoinInBattlegroundQueue(_player, guid, bgTypeId, joinAsGroup, err) && err <= 0)
|
||||
{
|
||||
WorldPacket data;
|
||||
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
|
||||
@@ -423,7 +424,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
|
||||
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenaType);
|
||||
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
|
||||
|
||||
if (!sScriptMgr->CanBattleFieldPort(_player, arenaType, bgTypeId, action))
|
||||
if (!sScriptMgr->OnPlayerCanBattleFieldPort(_player, arenaType, bgTypeId, action))
|
||||
return;
|
||||
|
||||
// get group info from queue
|
||||
@@ -578,11 +579,11 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_LEAVE_QUEUE);
|
||||
sScriptMgr->OnPlayerBattlegroundDesertion(_player, BG_DESERTION_TYPE_LEAVE_QUEUE);
|
||||
}
|
||||
|
||||
if (bg->isArena() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
|
||||
sScriptMgr->OnBattlegroundDesertion(_player, ARENA_DESERTION_TYPE_LEAVE_QUEUE);
|
||||
sScriptMgr->OnPlayerBattlegroundDesertion(_player, ARENA_DESERTION_TYPE_LEAVE_QUEUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,7 +748,7 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
|
||||
// queue result (default ok)
|
||||
GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult(bgt->GetBgTypeID());
|
||||
|
||||
if (!sScriptMgr->CanJoinInArenaQueue(_player, guid, arenaslot, bgTypeId, asGroup, isRated, err) && err <= 0)
|
||||
if (!sScriptMgr->OnPlayerCanJoinInArenaQueue(_player, guid, arenaslot, bgTypeId, asGroup, isRated, err) && err <= 0)
|
||||
{
|
||||
WorldPacket data;
|
||||
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
|
||||
@@ -812,7 +813,7 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
|
||||
if (isRated)
|
||||
{
|
||||
// pussywizard: for rated matches check if season is in progress!
|
||||
if (!sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS))
|
||||
if (sArenaSeasonMgr->GetSeasonState() == ARENA_SEASON_STATE_DISABLED)
|
||||
return;
|
||||
|
||||
ateamId = _player->GetArenaTeamId(arenaslot);
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
|
||||
LoginQueryHolder::LoginQueryHolder(uint32 accountId, ObjectGuid guid) : m_accountId(accountId), m_guid(guid)
|
||||
{
|
||||
@@ -607,7 +608,7 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData)
|
||||
uint32 initAccountId = GetAccountId();
|
||||
|
||||
// can't delete loaded character
|
||||
if (ObjectAccessor::FindConnectedPlayer(guid) || sWorld->FindOfflineSessionForCharacterGUID(guid.GetCounter()))
|
||||
if (ObjectAccessor::FindConnectedPlayer(guid) || sWorldSessionMgr->FindOfflineSessionForCharacterGUID(guid.GetCounter()))
|
||||
{
|
||||
sScriptMgr->OnPlayerFailedDelete(guid, initAccountId);
|
||||
return;
|
||||
@@ -693,14 +694,14 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recvData)
|
||||
};
|
||||
|
||||
// pussywizard:
|
||||
if (WorldSession* sess = sWorld->FindOfflineSessionForCharacterGUID(playerGuid.GetCounter()))
|
||||
if (WorldSession* sess = sWorldSessionMgr->FindOfflineSessionForCharacterGUID(playerGuid.GetCounter()))
|
||||
if (sess->GetAccountId() != GetAccountId())
|
||||
{
|
||||
SendCharLogin(CHAR_LOGIN_DUPLICATE_CHARACTER);
|
||||
return;
|
||||
}
|
||||
// pussywizard:
|
||||
if (WorldSession* sess = sWorld->FindOfflineSession(GetAccountId()))
|
||||
if (WorldSession* sess = sWorldSessionMgr->FindOfflineSession(GetAccountId()))
|
||||
{
|
||||
Player* p = sess->GetPlayer();
|
||||
if (!p || sess->IsKicked())
|
||||
@@ -956,7 +957,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
|
||||
if (sWorld->IsFFAPvPRealm() && !pCurrChar->IsGameMaster() && !pCurrChar->HasPlayerFlag(PLAYER_FLAGS_RESTING))
|
||||
if (!pCurrChar->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
|
||||
{
|
||||
sScriptMgr->OnFfaPvpStateUpdate(pCurrChar,true);
|
||||
sScriptMgr->OnPlayerFfaPvpStateUpdate(pCurrChar,true);
|
||||
pCurrChar->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
|
||||
}
|
||||
|
||||
@@ -1096,7 +1097,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
|
||||
{
|
||||
bool isReferrer = pCurrChar->GetSession()->IsARecruiter();
|
||||
|
||||
for (auto const& [accID, session] : sWorld->GetAllSessions())
|
||||
for (auto const& [accID, session] : sWorldSessionMgr->GetAllSessions())
|
||||
{
|
||||
if (!session->GetRecruiterId() && !session->IsARecruiter())
|
||||
continue;
|
||||
@@ -1118,7 +1119,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
|
||||
if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST))
|
||||
{
|
||||
pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST);
|
||||
sScriptMgr->OnFirstLogin(pCurrChar);
|
||||
sScriptMgr->OnPlayerFirstLogin(pCurrChar);
|
||||
}
|
||||
|
||||
METRIC_EVENT("player_events", "Login", pCurrChar->GetName());
|
||||
@@ -1385,7 +1386,7 @@ void WorldSession::HandleCharRenameCallBack(std::shared_ptr<CharacterRenameInfo>
|
||||
atLoginFlags &= ~AT_LOGIN_RENAME;
|
||||
|
||||
// pussywizard:
|
||||
if (ObjectAccessor::FindConnectedPlayer(ObjectGuid::Create<HighGuid::Player>(guidLow)) || sWorld->FindOfflineSessionForCharacterGUID(guidLow))
|
||||
if (ObjectAccessor::FindConnectedPlayer(ObjectGuid::Create<HighGuid::Player>(guidLow)) || sWorldSessionMgr->FindOfflineSessionForCharacterGUID(guidLow))
|
||||
{
|
||||
SendCharRename(CHAR_CREATE_ERROR, renameInfo.get());
|
||||
return;
|
||||
@@ -1621,7 +1622,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
// pussywizard:
|
||||
if (ObjectAccessor::FindConnectedPlayer(customizeInfo->Guid) || sWorld->FindOfflineSessionForCharacterGUID(customizeInfo->Guid.GetCounter()))
|
||||
if (ObjectAccessor::FindConnectedPlayer(customizeInfo->Guid) || sWorldSessionMgr->FindOfflineSessionForCharacterGUID(customizeInfo->Guid.GetCounter()))
|
||||
{
|
||||
recvData.rfinish();
|
||||
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
|
||||
@@ -1923,7 +1924,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
|
||||
>> factionChangeInfo->Race;
|
||||
|
||||
// pussywizard:
|
||||
if (ObjectAccessor::FindConnectedPlayer(factionChangeInfo->Guid) || sWorld->FindOfflineSessionForCharacterGUID(factionChangeInfo->Guid.GetCounter()))
|
||||
if (ObjectAccessor::FindConnectedPlayer(factionChangeInfo->Guid) || sWorldSessionMgr->FindOfflineSessionForCharacterGUID(factionChangeInfo->Guid.GetCounter()))
|
||||
{
|
||||
SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
|
||||
return;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user