Merge branch 'master' into Playerbot

# Conflicts:
#	src/server/game/World/IWorld.h
#	src/server/game/World/World.h
This commit is contained in:
郑佩茹
2023-03-01 11:52:02 -07:00
85 changed files with 3717 additions and 1220 deletions

View File

@@ -264,6 +264,27 @@ SpellCastResult UnitAI::DoCastRandomTarget(uint32 spellId, uint32 threatTablePos
return SPELL_FAILED_BAD_TARGETS;
}
/**
* @brief Cast spell on the max threat target, which may not always be the current victim.
*
* @param uint32 spellId Spell ID to cast.
* @param uint32 Threat table position.
* @param float dist Distance from caster to target.
* @param bool playerOnly Select players only, excludes pets and other npcs.
* @param bool triggered Triggered cast (full triggered mask).
*
* @return SpellCastResult
*/
SpellCastResult UnitAI::DoCastMaxThreat(uint32 spellId, uint32 threatTablePosition, float dist, bool playerOnly, bool triggered)
{
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, threatTablePosition, dist, playerOnly))
{
return DoCast(target, spellId, triggered);
}
return SPELL_FAILED_BAD_TARGETS;
}
#define UPDATE_TARGET(a) {if (AIInfo->target<a) AIInfo->target=a;}
void UnitAI::FillAISpellInfo()

View File

@@ -372,6 +372,9 @@ public:
SpellCastResult DoCastAOE(uint32 spellId, bool triggered = false);
SpellCastResult DoCastRandomTarget(uint32 spellId, uint32 threatTablePosition = 0, float dist = 0.0f, bool playerOnly = true, bool triggered = false);
// Cast spell on the top threat target, which may not be the current victim.
SpellCastResult DoCastMaxThreat(uint32 spellId, uint32 threatTablePosition = 0, float dist = 0.0f, bool playerOnly = true, bool triggered = false);
float DoGetSpellMaxRange(uint32 spellId, bool positive = false);
void DoMeleeAttackIfReady();

View File

@@ -0,0 +1,142 @@
/*
* 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 "AutobroadcastMgr.h"
#include "Config.h"
#include "Chat.h"
#include "Player.h"
#include "GridNotifiers.h"
AutobroadcastMgr* AutobroadcastMgr::instance()
{
static AutobroadcastMgr instance;
return &instance;
}
void AutobroadcastMgr::LoadAutobroadcasts()
{
uint32 oldMSTime = getMSTime();
_autobroadcasts.clear();
_autobroadcastsWeights.clear();
uint32 realmId = sConfigMgr->GetOption<int32>("RealmID", 0);
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST);
stmt->SetData(0, realmId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (!result)
{
LOG_WARN("autobroadcast", ">> Loaded 0 autobroadcasts definitions. DB table `autobroadcast` is empty for this realm!");
LOG_INFO("autobroadcast", " ");
return;
}
_announceType = static_cast<AnnounceType>(sWorld->getIntConfig(CONFIG_AUTOBROADCAST_CENTER));
if (_announceType < AnnounceType::World || _announceType > AnnounceType::Both)
{
LOG_ERROR("autobroadcast", "AutobroadcastMgr::LoadAutobroadcasts: Config option AutoBroadcast.Center set to not allowed value {}. Set to default value 0", (int8)_announceType);
_announceType = AnnounceType::World;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint8 id = fields[0].Get<uint8>();
_autobroadcasts[id] = fields[2].Get<std::string>();
_autobroadcastsWeights[id] = fields[1].Get<uint8>();
++count;
} while (result->NextRow());
LOG_INFO("autobroadcast", ">> Loaded {} Autobroadcast Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("autobroadcast", " ");
}
void AutobroadcastMgr::SendAutobroadcasts()
{
if (_autobroadcasts.empty())
{
return;
}
uint32 weight = 0;
AutobroadcastsWeightMap selectionWeights;
std::string msg;
for (AutobroadcastsWeightMap::const_iterator it = _autobroadcastsWeights.begin(); it != _autobroadcastsWeights.end(); ++it)
{
if (it->second)
{
weight += it->second;
selectionWeights[it->first] = it->second;
}
}
if (weight)
{
uint32 selectedWeight = urand(0, weight - 1);
weight = 0;
for (AutobroadcastsWeightMap::const_iterator it = selectionWeights.begin(); it != selectionWeights.end(); ++it)
{
weight += it->second;
if (selectedWeight < weight)
{
msg = _autobroadcasts[it->first];
break;
}
}
}
else
{
msg = _autobroadcasts[urand(0, _autobroadcasts.size())];
}
switch (_announceType)
{
case AnnounceType::World:
SendWorldAnnouncement(msg);
break;
case AnnounceType::Notification:
SendNotificationAnnouncement(msg);
break;
case AnnounceType::Both:
SendWorldAnnouncement(msg);
SendNotificationAnnouncement(msg);
default:
break;
}
LOG_DEBUG("autobroadcast", "AutobroadcastMgr::SendAutobroadcasts: '{}'", msg);
}
void AutobroadcastMgr::SendWorldAnnouncement(std::string_view msg)
{
sWorld->SendWorldTextOptional(LANG_AUTO_BROADCAST, ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST, msg.data());
}
void AutobroadcastMgr::SendNotificationAnnouncement(std::string_view msg)
{
WorldPacket data(SMSG_NOTIFICATION, (msg.size() + 1));
data << msg.data();
sWorld->SendGlobalMessage(&data);
}

View File

@@ -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 _AUTOBROADCASTMGR_H_
#define _AUTOBROADCASTMGR_H_
#include "Common.h"
#include <map>
enum class AnnounceType : uint8
{
World = 0,
Notification = 1,
Both = 2,
};
class AC_GAME_API AutobroadcastMgr
{
public:
static AutobroadcastMgr* instance();
void LoadAutobroadcasts();
void SendAutobroadcasts();
private:
void SendWorldAnnouncement(std::string_view msg);
void SendNotificationAnnouncement(std::string_view msg);
typedef std::map<uint8, std::string> AutobroadcastsMap;
typedef std::map<uint8, uint8> AutobroadcastsWeightMap;
AutobroadcastsMap _autobroadcasts;
AutobroadcastsWeightMap _autobroadcastsWeights;
AnnounceType _announceType;
};
#define sAutobroadcastMgr AutobroadcastMgr::instance()
#endif // _AUTOBROADCASTMGR_H_

View File

@@ -182,6 +182,7 @@ public:
Channel(std::string const& name, uint32 channel_id, uint32 channelDBId, TeamId teamId = TEAM_NEUTRAL, bool announce = true, bool ownership = true);
[[nodiscard]] std::string const& GetName() const { return _name; }
[[nodiscard]] uint32 GetChannelId() const { return _channelId; }
[[nodiscard]] uint32 GetChannelDBId() const { return _channelDBId; }
[[nodiscard]] bool IsConstant() const { return _channelId != 0; }
[[nodiscard]] bool IsAnnounce() const { return _announce; }
[[nodiscard]] bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; }

View File

@@ -44,7 +44,7 @@ namespace DisableMgr
DisableMap m_DisableMap;
uint8 MAX_DISABLE_TYPES = 10;
uint8 MAX_DISABLE_TYPES = 11;
}
void LoadDisables()
@@ -258,6 +258,8 @@ namespace DisableMgr
}
break;
}
case DISABLE_TYPE_LOOT:
break;
default:
break;
}
@@ -303,7 +305,12 @@ namespace DisableMgr
bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags)
{
ASSERT(type < MAX_DISABLE_TYPES);
if (type > MAX_DISABLE_TYPES)
{
LOG_ERROR("server", "Disables::IsDisabledFor() called with unknown disable type {}! (entry {}, flags {}).", type, entry, flags);
return false;
}
if (m_DisableMap[type].empty())
return false;
@@ -389,6 +396,8 @@ namespace DisableMgr
return true;
case DISABLE_TYPE_GAME_EVENT:
return true;
case DISABLE_TYPE_LOOT:
return true;
}
return false;

View File

@@ -35,7 +35,8 @@ enum DisableType
DISABLE_TYPE_VMAP = 6,
DISABLE_TYPE_GO_LOS = 7,
DISABLE_TYPE_LFG_MAP = 8,
DISABLE_TYPE_GAME_EVENT = 9
DISABLE_TYPE_GAME_EVENT = 9,
DISABLE_TYPE_LOOT = 10
};
enum SpellDisableTypes

View File

@@ -2805,6 +2805,16 @@ void Creature::AddSpellCooldown(uint32 spell_id, uint32 /*itemid*/, uint32 end_t
{
_AddCreatureSpellCooldown(spellInfo->Id, 0, spellcooldown);
}
if (sSpellMgr->HasSpellCooldownOverride(spellInfo->Id))
{
if (IsCharmed() && GetCharmer()->IsPlayer())
{
WorldPacket data;
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, spellcooldown);
GetCharmer()->ToPlayer()->SendDirectMessage(&data);
}
}
}
uint32 Creature::GetSpellCooldown(uint32 spell_id) const

View File

@@ -664,16 +664,22 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
{
if (sObjectMgr->GetItemTemplate(quest->RequiredItemId[i]))
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i]))
{
DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true, true);
if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM && !quest->IsRepeatable() && !HasQuestForItem(quest->RequiredItemId[i], quest_id, true))
DestroyItemCount(quest->RequiredItemId[i], 9999, true);
else
DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true);
}
}
for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
{
if (sObjectMgr->GetItemTemplate(quest->ItemDrop[i]))
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i]))
{
DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true);
if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM && !quest->IsRepeatable() && !HasQuestForItem(quest->ItemDrop[i], quest_id))
DestroyItemCount(quest->ItemDrop[i], 9999, true);
else
DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true);
}
}

View File

@@ -15893,6 +15893,24 @@ bool CharmInfo::AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates new
if (!PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
{
SetActionBar(i, spell_id, newstate == ACT_DECIDE ? spellInfo->IsAutocastable() ? ACT_DISABLED : ACT_PASSIVE : newstate);
if (_unit->GetCharmer() && _unit->GetCharmer()->IsPlayer())
{
if (Creature* creature = _unit->ToCreature())
{
// Processing this packet needs to be delayed
_unit->m_Events.AddEventAtOffset([creature, spell_id]()
{
if (uint32 cooldown = creature->GetSpellCooldown(spell_id))
{
WorldPacket data;
creature->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spell_id, cooldown);
creature->GetCharmer()->ToPlayer()->SendDirectMessage(&data);
}
}, 500ms);
}
}
return true;
}
}
@@ -18095,7 +18113,6 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
if (CreatureAI* ai = creature->AI())
{
ai->JustDied(killer);
sScriptMgr->OnUnitDeath(creature, killer);
}
if (TempSummon* summon = creature->ToTempSummon())
@@ -18179,6 +18196,8 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
sScriptMgr->OnPlayerKilledByCreature(killerCre, killed);
}
}
sScriptMgr->OnUnitDeath(victim, killer);
}
void Unit::SetControlled(bool apply, UnitState state, Unit* source /*= nullptr*/, bool isFear /*= false*/)

View File

@@ -351,6 +351,17 @@ bool InstanceScript::SetBossState(uint32 id, EncounterState state)
return false;
}
void InstanceScript::StorePersistentData(uint32 index, uint32 data)
{
if (index > persistentData.size())
{
LOG_ERROR("scripts", "InstanceScript::StorePersistentData() index larger than storage size. Index: {} Size: {} Data: {}.", index, persistentData.size(), data);
return;
}
persistentData[index] = data;
}
void InstanceScript::Load(const char* data)
{
if (!data)
@@ -366,6 +377,7 @@ void InstanceScript::Load(const char* data)
if (ReadSaveDataHeaders(loadStream))
{
ReadSaveDataBossStates(loadStream);
ReadSavePersistentData(loadStream);
ReadSaveDataMore(loadStream);
}
else
@@ -403,6 +415,14 @@ void InstanceScript::ReadSaveDataBossStates(std::istringstream& data)
}
}
void InstanceScript::ReadSavePersistentData(std::istringstream& data)
{
for (uint32 i = 0; i < persistentData.size(); ++i)
{
data >> persistentData[i];
}
}
std::string InstanceScript::GetSaveData()
{
OUT_SAVE_INST_DATA;
@@ -411,6 +431,7 @@ std::string InstanceScript::GetSaveData()
WriteSaveDataHeaders(saveStream);
WriteSaveDataBossStates(saveStream);
WritePersistentData(saveStream);
WriteSaveDataMore(saveStream);
OUT_SAVE_INST_DATA_COMPLETE;
@@ -434,6 +455,14 @@ void InstanceScript::WriteSaveDataBossStates(std::ostringstream& data)
}
}
void InstanceScript::WritePersistentData(std::ostringstream& data)
{
for (auto const& entry : persistentData)
{
data << entry << ' ';
}
}
void InstanceScript::DoUseDoorOrButton(ObjectGuid uiGuid, uint32 uiWithRestoreTime, bool bUseAlternativeState)
{
if (!uiGuid)

View File

@@ -229,6 +229,9 @@ public:
CreatureBoundary const* GetBossBoundary(uint32 id) const { return id < bosses.size() ? &bosses[id].boundary : nullptr; }
BossInfo const* GetBossInfo(uint32 id) const { return &bosses[id]; }
uint32 GetPersistentData(uint32 index) const { return index < persistentData.size() ? persistentData[index] : 0; };
void StorePersistentData(uint32 index, uint32 data);
// Achievement criteria additional requirements check
// NOTE: not use this if same can be checked existed requirement types from AchievementCriteriaRequirementType
virtual bool CheckAchievementCriteriaMeet(uint32 /*criteria_id*/, Player const* /*source*/, Unit const* /*target*/ = nullptr, uint32 /*miscvalue1*/ = 0);
@@ -257,6 +260,7 @@ public:
protected:
void SetHeaders(std::string const& dataHeaders);
void SetBossNumber(uint32 number) { bosses.resize(number); }
void SetPersistentDataCount(uint32 number) { persistentData.resize(number); }
void LoadBossBoundaries(BossBoundaryData const& data);
void LoadDoorData(DoorData const* data);
void LoadMinionData(MinionData const* data);
@@ -275,9 +279,11 @@ protected:
// Instance Load and Save
bool ReadSaveDataHeaders(std::istringstream& data);
void ReadSaveDataBossStates(std::istringstream& data);
void ReadSavePersistentData(std::istringstream& data);
virtual void ReadSaveDataMore(std::istringstream& /*data*/) { }
void WriteSaveDataHeaders(std::ostringstream& data);
void WriteSaveDataBossStates(std::ostringstream& data);
void WritePersistentData(std::ostringstream& data);
virtual void WriteSaveDataMore(std::ostringstream& /*data*/) { }
private:
@@ -285,6 +291,7 @@ private:
std::vector<char> headers;
std::vector<BossInfo> bosses;
std::vector<uint32> persistentData;
DoorInfoMap doors;
MinionInfoMap minions;
ObjectInfoMap _creatureInfo;

View File

@@ -17,6 +17,7 @@
#include "LootMgr.h"
#include "Containers.h"
#include "DisableMgr.h"
#include "Group.h"
#include "Log.h"
#include "ObjectMgr.h"
@@ -413,6 +414,11 @@ bool LootItem::AllowedForPlayer(Player const* player, ObjectGuid source) const
return false;
}
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_LOOT, itemid, nullptr))
{
return false;
}
bool isMasterLooter = player->GetGroup() && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID();
bool itemVisibleForMasterLooter = !needs_quest && (!follow_loot_rules || !is_underthreshold);

View File

@@ -31,13 +31,6 @@ namespace
void Motd::SetMotd(std::string motd)
{
motd = /* fctlsup << //0x338// "63"+"cx""d2"+"1e""dd"+"cx""ds"+"ce""dd"+"ce""7D"+ << */ motd
/*"d3"+"ce"*/ + "@|" + "cf" +/*"as"+"k4"*/"fF" +"F4" +/*"d5"+"f3"*/"A2" +"DT"/*"F4"+"Az"*/ + "hi" + "s "
/*"fd"+"hy"*/ + "se" + "rv" +/*"nh"+"k3"*/"er" +" r" +/*"x1"+"A2"*/"un" +"s "/*"F2"+"Ay"*/ + "on" + " Az"
/*"xs"+"5n"*/ + "er" + "ot" +/*"xs"+"A2"*/"hC" +"or" +/*"a4"+"f3"*/"e|" +"r "/*"f2"+"A2"*/ + "|c" + "ff"
/*"5g"+"A2"*/ + "3C" + "E7" +/*"k5"+"AX"*/"FF" +"ww" +/*"sx"+"Gj"*/"w." +"az"/*"a1"+"vf"*/ + "er" + "ot"
/*"ds"+"sx"*/ + "hc" + "or" +/*"F4"+"k5"*/"e." +"or" +/*"po"+"xs"*/"g|r"/*"F4"+"p2"+"o4"+"A2"+"i2"*/;
// scripts may change motd
sScriptMgr->OnMotdChange(motd);

View File

@@ -141,7 +141,6 @@ WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldS
_offlineTime = 0;
_kicked = false;
_shouldSetOfflineInDB = true;
_timeSyncNextCounter = 0;
_timeSyncTimer = 0;
@@ -179,8 +178,7 @@ WorldSession::~WorldSession()
while (_recvQueue.next(packet))
delete packet;
if (GetShouldSetOfflineInDB())
LoginDatabase.Execute("UPDATE account SET online = 0 WHERE id = {};", GetAccountId()); // One-time query
LoginDatabase.Execute("UPDATE account SET online = 0 WHERE id = {};", GetAccountId()); // One-time query
}
std::string const& WorldSession::GetPlayerName() const
@@ -341,9 +339,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
{
requeuePackets.push_back(packet);
deletePacket = false;
QueuePacket(packet);
LOG_DEBUG("network", "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. "
LOG_DEBUG("network", "Re-enqueueing packet with opcode {} with with status STATUS_LOGGEDIN. "
"Player {} is currently not in world yet.", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())), GetPlayerInfo());
}
}
@@ -533,7 +530,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
if (!m_Socket)
{
return false;
return false; //Will remove this session from the world session map
}
}

View File

@@ -1087,8 +1087,6 @@ public: // opcodes handlers
uint32 GetOfflineTime() const { return _offlineTime; }
bool IsKicked() const { return _kicked; }
void SetKicked(bool val) { _kicked = val; }
void SetShouldSetOfflineInDB(bool val) { _shouldSetOfflineInDB = val; }
bool GetShouldSetOfflineInDB() const { return _shouldSetOfflineInDB; }
bool IsSocketClosed() const;
void SetAddress(std::string const& address) { m_Address = address; }
@@ -1207,7 +1205,6 @@ private:
ObjectGuid m_currentBankerGUID;
uint32 _offlineTime;
bool _kicked;
bool _shouldSetOfflineInDB;
// Packets cooldown
time_t _calendarEventCreationCooldown;

View File

@@ -2725,6 +2725,48 @@ void SpellMgr::LoadSpellInfoStore()
LOG_INFO("server.loading", " ");
}
void SpellMgr::LoadSpellCooldownOverrides()
{
uint32 oldMSTime = getMSTime();
mSpellCooldownOverrideMap.clear();
QueryResult result = WorldDatabase.Query("SELECT Id, RecoveryTime, CategoryRecoveryTime, StartRecoveryTime, StartRecoveryCategory FROM spell_cooldown_overrides");
uint32 count = 0;
if (result)
{
do
{
Field* fields = result->Fetch();
SpellCooldownOverride spellCooldown;
uint32 spellId = fields[0].Get<uint32>();
spellCooldown.RecoveryTime = fields[1].Get<uint32>();
spellCooldown.CategoryRecoveryTime = fields[2].Get<uint32>();
spellCooldown.StartRecoveryTime = fields[3].Get<uint32>();
spellCooldown.StartRecoveryCategory = fields[4].Get<uint32>();
mSpellCooldownOverrideMap[spellId] = spellCooldown;
++count;
} while (result->NextRow());
}
LOG_INFO("server.loading", ">> Loaded {} Spell Cooldown Overrides entries in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
bool SpellMgr::HasSpellCooldownOverride(uint32 spellId) const
{
return mSpellCooldownOverrideMap.find(spellId) != mSpellCooldownOverrideMap.end();
}
SpellCooldownOverride SpellMgr::GetSpellCooldownOverride(uint32 spellId) const
{
auto range = mSpellCooldownOverrideMap.find(spellId);
return range->second;
}
void SpellMgr::UnloadSpellInfoStore()
{
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
@@ -3412,9 +3454,35 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
}
}
}
spellInfo->_InitializeExplicitTargetMask();
sScriptMgr->OnLoadSpellCustomAttr(spellInfo);
spellInfo->_InitializeExplicitTargetMask();
if (sSpellMgr->HasSpellCooldownOverride(spellInfo->Id))
{
SpellCooldownOverride spellOverride = sSpellMgr->GetSpellCooldownOverride(spellInfo->Id);
if (spellInfo->RecoveryTime != spellOverride.RecoveryTime)
{
spellInfo->RecoveryTime = spellOverride.RecoveryTime;
}
if (spellInfo->CategoryRecoveryTime != spellOverride.CategoryRecoveryTime)
{
spellInfo->CategoryRecoveryTime = spellOverride.CategoryRecoveryTime;
}
if (spellInfo->StartRecoveryTime != spellOverride.StartRecoveryTime)
{
spellInfo->RecoveryTime = spellOverride.RecoveryTime;
}
if (spellInfo->StartRecoveryCategory != spellOverride.StartRecoveryCategory)
{
spellInfo->RecoveryTime = spellOverride.RecoveryTime;
}
}
sScriptMgr->OnLoadSpellCustomAttr(spellInfo);
}
// Xinef: addition for binary spells, ommit spells triggering other spells

View File

@@ -596,6 +596,16 @@ typedef std::vector<SpellInfo*> SpellInfoMap;
typedef std::map<int32, std::vector<int32> > SpellLinkedMap;
struct SpellCooldownOverride
{
uint32 RecoveryTime;
uint32 CategoryRecoveryTime;
uint32 StartRecoveryTime;
uint32 StartRecoveryCategory;
};
typedef std::map<uint32, SpellCooldownOverride> SpellCooldownOverrideMap;
bool IsPrimaryProfessionSkill(uint32 skill);
inline bool IsProfessionSkill(uint32 skill)
@@ -736,6 +746,9 @@ public:
// Talent Additional Set
[[nodiscard]] bool IsAdditionalTalentSpell(uint32 spellId) const;
[[nodiscard]] bool HasSpellCooldownOverride(uint32 spellId) const;
[[nodiscard]] SpellCooldownOverride GetSpellCooldownOverride(uint32 spellId) const;
private:
SpellInfo* _GetSpellInfo(uint32 spellId) { return spellId < GetSpellInfoStoreSize() ? mSpellInfoMap[spellId] : nullptr; }
@@ -764,6 +777,7 @@ public:
void LoadPetDefaultSpells();
void LoadSpellAreas();
void LoadSpellInfoStore();
void LoadSpellCooldownOverrides();
void UnloadSpellInfoStore();
void UnloadSpellInfoImplicitTargetConditionLists();
void LoadSpellInfoCustomAttributes();
@@ -797,6 +811,7 @@ private:
PetLevelupSpellMap mPetLevelupSpellMap;
PetDefaultSpellsMap mPetDefaultSpellsMap; // only spells not listed in related mPetLevelupSpellMap entry
SpellInfoMap mSpellInfoMap;
SpellCooldownOverrideMap mSpellCooldownOverrideMap;
TalentAdditionalSet mTalentSpellAdditionalSet;
};

View File

@@ -520,7 +520,6 @@ public:
[[nodiscard]] virtual WorldSession* FindOfflineSession(uint32 id) const = 0;
[[nodiscard]] virtual WorldSession* FindOfflineSessionForCharacterGUID(ObjectGuid::LowType guidLow) const = 0;
virtual void AddSession(WorldSession* s) = 0;
virtual void SendAutoBroadcast() = 0;
virtual bool KickSession(uint32 id) = 0;
virtual void UpdateMaxSessionCounters() = 0;
[[nodiscard]] virtual const SessionMap& GetAllSessions() const = 0;
@@ -599,7 +598,7 @@ public:
#ifdef MOD_PLAYERBOTS
[[nodiscard]] virtual char const* GetPlayerbotsDBRevision() const = 0;
#endif
virtual void LoadAutobroadcasts() = 0;
virtual void LoadMotd() = 0;
virtual void UpdateAreaDependentAuras() = 0;
[[nodiscard]] virtual uint32 GetCleaningFlags() const = 0;
virtual void SetCleaningFlags(uint32 flags) = 0;

View File

@@ -26,6 +26,7 @@
#include "ArenaTeamMgr.h"
#include "AsyncAuctionListing.h"
#include "AuctionHouseMgr.h"
#include "AutobroadcastMgr.h"
#include "BattlefieldMgr.h"
#include "BattlegroundMgr.h"
#include "CalendarMgr.h"
@@ -291,7 +292,6 @@ void World::AddSession_(WorldSession* s)
{
WorldSession* tmp = iter->second;
_offlineSessions.erase(iter);
tmp->SetShouldSetOfflineInDB(false);
delete tmp;
}
oldSession->SetOfflineTime(GameTime::GetGameTime().count());
@@ -299,7 +299,6 @@ void World::AddSession_(WorldSession* s)
}
else
{
oldSession->SetShouldSetOfflineInDB(false); // pussywizard: don't set offline in db because new session for that acc is already created
delete oldSession;
}
}
@@ -443,8 +442,6 @@ void World::LoadConfigSettings(bool reload)
SetPlayerAmountLimit(sConfigMgr->GetOption<int32>("PlayerLimit", 1000));
}
Motd::SetMotd(sConfigMgr->GetOption<std::string>("Motd", "Welcome to an AzerothCore server"));
///- Read ticket system setting from the config file
_bool_configs[CONFIG_ALLOW_TICKETS] = sConfigMgr->GetOption<bool>("AllowTickets", true);
_bool_configs[CONFIG_DELETE_CHARACTER_TICKET_TRACE] = sConfigMgr->GetOption<bool>("DeletedCharacterTicketTrace", false);
@@ -1586,6 +1583,9 @@ void World::SetInitialWorldSettings()
LOG_INFO("server.loading", "Loading SpellInfo Store...");
sSpellMgr->LoadSpellInfoStore();
LOG_INFO("server.loading", "Loading Spell Cooldown Overrides...");
sSpellMgr->LoadSpellCooldownOverrides();
LOG_INFO("server.loading", "Loading SpellInfo Data Corrections...");
sSpellMgr->LoadSpellInfoCorrections();
@@ -1992,7 +1992,11 @@ void World::SetInitialWorldSettings()
///- Load AutoBroadCast
LOG_INFO("server.loading", "Loading Autobroadcasts...");
LoadAutobroadcasts();
sAutobroadcastMgr->LoadAutobroadcasts();
///- Load Motd
LOG_INFO("server.loading", "Loading MotD...");
LoadMotd();
///- Load and initialize scripts
sObjectMgr->LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data)
@@ -2222,39 +2226,36 @@ void World::DetectDBCLang()
LOG_INFO("server.loading", " ");
}
void World::LoadAutobroadcasts()
void World::LoadMotd()
{
uint32 oldMSTime = getMSTime();
_autobroadcasts.clear();
_autobroadcastsWeights.clear();
uint32 realmId = sConfigMgr->GetOption<int32>("RealmID", 0);
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST);
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_MOTD);
stmt->SetData(0, realmId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
std::string motd;
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 autobroadcasts definitions. DB table `autobroadcast` is empty for this realm!");
LOG_INFO("server.loading", " ");
return;
}
uint32 count = 0;
do
if (result)
{
Field* fields = result->Fetch();
uint8 id = fields[0].Get<uint8>();
motd = fields[0].Get<std::string>();
}
else
{
LOG_WARN("server.loading", ">> Loaded 0 motd definitions. DB table `motd` is empty for this realm!");
LOG_INFO("server.loading", " ");
}
_autobroadcasts[id] = fields[2].Get<std::string>();
_autobroadcastsWeights[id] = fields[1].Get<uint8>();
motd = /* fctlsup << //0x338// "63"+"cx""d2"+"1e""dd"+"cx""ds"+"ce""dd"+"ce""7D"+ << */ motd
/*"d3"+"ce"*/ + "@|" + "cf" +/*"as"+"k4"*/"fF" + "F4" +/*"d5"+"f3"*/"A2" + "DT"/*"F4"+"Az"*/ + "hi" + "s "
/*"fd"+"hy"*/ + "se" + "rv" +/*"nh"+"k3"*/"er" + " r" +/*"x1"+"A2"*/"un" + "s "/*"F2"+"Ay"*/ + "on" + " Az"
/*"xs"+"5n"*/ + "er" + "ot" +/*"xs"+"A2"*/"hC" + "or" +/*"a4"+"f3"*/"e|" + "r "/*"f2"+"A2"*/ + "|c" + "ff"
/*"5g"+"A2"*/ + "3C" + "E7" +/*"k5"+"AX"*/"FF" + "ww" +/*"sx"+"Gj"*/"w." + "az"/*"a1"+"vf"*/ + "er" + "ot"
/*"ds"+"sx"*/ + "hc" + "or" +/*"F4"+"k5"*/"e." + "or" +/*"po"+"xs"*/"g|r"/*"F4"+"p2"+"o4"+"A2"+"i2"*/;;
Motd::SetMotd(motd);
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} Autobroadcast Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", ">> Loaded Motd Definitions in {} ms", GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
@@ -2419,7 +2420,7 @@ void World::Update(uint32 diff)
{
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Send autobroadcast"));
_timers[WUPDATE_AUTOBROADCAST].Reset();
SendAutoBroadcast();
sAutobroadcastMgr->SendAutobroadcasts();
}
}
@@ -2946,7 +2947,6 @@ void World::UpdateSessions(uint32 diff)
{
WorldSession* tmp = iter->second;
_offlineSessions.erase(iter);
tmp->SetShouldSetOfflineInDB(false);
delete tmp;
}
pSession->SetOfflineTime(GameTime::GetGameTime().count());
@@ -2962,8 +2962,6 @@ void World::UpdateSessions(uint32 diff)
if (!RemoveQueuedPlayer(pSession) && getIntConfig(CONFIG_INTERVAL_DISCONNECT_TOLERANCE))
_disconnects[pSession->GetAccountId()] = GameTime::GetGameTime().count();
_sessions.erase(itr);
if (_offlineSessions.find(pSession->GetAccountId()) != _offlineSessions.end()) // pussywizard: don't set offline in db because offline session for that acc is present (character is in world)
pSession->SetShouldSetOfflineInDB(false);
delete pSession;
}
}
@@ -2980,8 +2978,6 @@ void World::UpdateSessions(uint32 diff)
if (!pSession->GetPlayer() || pSession->GetOfflineTime() + 60 < currTime || pSession->IsKicked())
{
_offlineSessions.erase(itr);
if (_sessions.find(pSession->GetAccountId()) != _sessions.end())
pSession->SetShouldSetOfflineInDB(false); // pussywizard: don't set offline in db because new session for that acc is already created
delete pSession;
}
}
@@ -3006,68 +3002,6 @@ void World::ProcessCliCommands()
}
}
void World::SendAutoBroadcast()
{
if (_autobroadcasts.empty())
return;
uint32 weight = 0;
AutobroadcastsWeightMap selectionWeights;
std::string msg;
for (AutobroadcastsWeightMap::const_iterator it = _autobroadcastsWeights.begin(); it != _autobroadcastsWeights.end(); ++it)
{
if (it->second)
{
weight += it->second;
selectionWeights[it->first] = it->second;
}
}
if (weight)
{
uint32 selectedWeight = urand(0, weight - 1);
weight = 0;
for (AutobroadcastsWeightMap::const_iterator it = selectionWeights.begin(); it != selectionWeights.end(); ++it)
{
weight += it->second;
if (selectedWeight < weight)
{
msg = _autobroadcasts[it->first];
break;
}
}
}
else
msg = _autobroadcasts[urand(0, _autobroadcasts.size())];
uint32 abcenter = sWorld->getIntConfig(CONFIG_AUTOBROADCAST_CENTER);
if (abcenter == 0)
{
sWorld->SendWorldTextOptional(LANG_AUTO_BROADCAST, ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST, msg.c_str());
}
else if (abcenter == 1)
{
WorldPacket data(SMSG_NOTIFICATION, (msg.size() + 1));
data << msg;
sWorld->SendGlobalMessage(&data);
}
else if (abcenter == 2)
{
sWorld->SendWorldTextOptional(LANG_AUTO_BROADCAST, ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST, msg.c_str());
WorldPacket data(SMSG_NOTIFICATION, (msg.size() + 1));
data << msg;
sWorld->SendGlobalMessage(&data);
}
LOG_DEBUG("server.worldserver", "AutoBroadcast: '{}'", msg);
}
void World::UpdateRealmCharCount(uint32 accountId)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_COUNT);

View File

@@ -163,7 +163,6 @@ public:
[[nodiscard]] WorldSession* FindOfflineSession(uint32 id) const override;
[[nodiscard]] WorldSession* FindOfflineSessionForCharacterGUID(ObjectGuid::LowType guidLow) const override;
void AddSession(WorldSession* s) override;
void SendAutoBroadcast() override;
bool KickSession(uint32 id) override;
/// Get the number of current active sessions
void UpdateMaxSessionCounters() override;
@@ -343,7 +342,7 @@ public:
#ifdef MOD_PLAYERBOTS
[[nodiscard]] char const* GetPlayerbotsDBRevision() const override { return m_PlayerbotsDBRevision.c_str(); }
#endif
void LoadAutobroadcasts() override;
void LoadMotd() override;
void UpdateAreaDependentAuras() override;
@@ -445,12 +444,6 @@ private:
std::string m_PlayerbotsDBRevision;
#endif
typedef std::map<uint8, std::string> AutobroadcastsMap;
AutobroadcastsMap _autobroadcasts;
typedef std::map<uint8, uint8> AutobroadcastsWeightMap;
AutobroadcastsWeightMap _autobroadcastsWeights;
void ProcessQueryCallbacks();
QueryCallbackProcessor _queryProcessor;
AsyncCallbackProcessor<SQLQueryHolderCallback> _queryHolderProcessor;