Merge pull request #7 from azerothcore/master

Merge
This commit is contained in:
kadeshar
2025-08-27 21:04:10 +02:00
committed by GitHub
79 changed files with 2648 additions and 291 deletions
@@ -72,6 +72,8 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
mcanSpawn = true;
_chaseOnInterrupt = false;
// Xinef: Vehicle conditions
m_ConditionsTimer = 0;
if (me->GetVehicleKit())
@@ -212,6 +212,9 @@ public:
// Xinef
void SetWPPauseTimer(uint32 time) { mWPPauseTimer = time; }
void SetChaseOnInterrupt(bool apply) { _chaseOnInterrupt = apply; }
[[nodiscard]] bool CanChaseOnInterrupt() const { return _chaseOnInterrupt; }
private:
bool mIsCharmed;
uint32 mFollowCreditType;
@@ -257,6 +260,8 @@ private:
void CheckConditions(const uint32 diff);
ConditionList conditions;
uint32 m_ConditionsTimer;
bool _chaseOnInterrupt;
};
class SmartGameObjectAI : public GameObjectAI
@@ -742,6 +742,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE)
{
CAST_AI(SmartAI, me->AI())->SetChaseOnInterrupt(true);
if (!me->isMoving()) // Don't try to reposition while we are moving
{
// If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed unless target is outside spell range, out of mana, or LOS.
@@ -893,7 +895,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
go->SetLootState(GO_READY);
}
go->UseDoorOrButton(0, !!e.action.activateObject.alternative, unit);
go->UseDoorOrButton(0, e.action.activateObject.alternative, unit);
LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. Gameobject {} activated", go->GetGUID().ToString());
}
}
@@ -1483,14 +1485,14 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
for (WorldObject* target : targets)
if (IsUnit(target))
target->ToUnit()->SetVisible(!!e.action.visibility.state);
target->ToUnit()->SetVisible(e.action.visibility.state);
break;
}
case SMART_ACTION_SET_ACTIVE:
{
for (WorldObject* target : targets)
target->setActive(!!e.action.setActive.state);
target->setActive(e.action.setActive.state);
break;
}
case SMART_ACTION_ATTACK_START:
@@ -202,10 +202,29 @@ void SmartAIMgr::LoadSmartAIFromDB()
}
else
{
if (!sObjectMgr->GetCreatureData(uint32(std::abs(temp.entryOrGuid))))
switch (source_type)
{
LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature guid ({}) does not exist, skipped loading.", uint32(std::abs(temp.entryOrGuid)));
continue;
case SMART_SCRIPT_TYPE_CREATURE:
{
if (!sObjectMgr->GetCreatureData(uint32(std::abs(temp.entryOrGuid))))
{
LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature guid ({}) does not exist, skipped loading.", uint32(std::abs(temp.entryOrGuid)));
continue;
}
break;
}
case SMART_SCRIPT_TYPE_GAMEOBJECT:
{
if (!sObjectMgr->GetGameObjectData(uint32(std::abs(temp.entryOrGuid))))
{
LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject guid ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
continue;
}
break;
}
default:
LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: not yet implemented source_type {}", (uint32)source_type);
continue;
}
}
@@ -488,7 +488,7 @@ void AuctionHouseObject::AddAuction(AuctionEntry* auction)
bool AuctionHouseObject::RemoveAuction(AuctionEntry* auction)
{
bool wasInMap = !!_auctionsMap.erase(auction->Id);
bool wasInMap = _auctionsMap.erase(auction->Id);
sAuctionMgr->GetAuctionHouseSearcher()->RemoveAuction(auction);
sScriptMgr->OnAuctionRemove(this, auction);
+1 -1
View File
@@ -206,7 +206,7 @@ bool Acore::Hyperlinks::LinkTags::spell::StoreTo(SpellInfo const*& val, std::str
if (!(t.TryConsumeTo(spellId) && t.IsEmpty()))
return false;
return !!(val = sSpellMgr->GetSpellInfo(spellId));
return (val = sSpellMgr->GetSpellInfo(spellId));
}
bool Acore::Hyperlinks::LinkTags::talent::StoreTo(TalentLinkData& val, std::string_view text)
+1 -1
View File
@@ -68,7 +68,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
{
// don't allow 0 items (it's checked during table load)
ASSERT(ConditionValue2);
bool checkBank = !!ConditionValue3;
bool checkBank = ConditionValue3;
condMeets = player->HasItemCount(ConditionValue1, ConditionValue2, checkBank);
}
}
@@ -1987,8 +1987,6 @@ void Creature::setDeathState(DeathState state, bool despawn)
Dismount(); // if creature is mounted on a virtual mount, remove it at death
setActive(false);
if (HasSearchedAssistance())
{
SetNoSearchAssistance(false);
@@ -3904,7 +3902,7 @@ bool Creature::IsUpdateNeeded()
if (IsInCombat())
return true;
if (IsVisibilityOverridden())
if (!GetObjectVisibilityContainer().GetVisiblePlayersMap().empty())
return true;
if (ToTempSummon())
@@ -67,7 +67,7 @@ struct FormationInfo
uint32 point_1;
uint32 point_2;
bool HasGroupFlag(uint16 flag) const { return !!(groupAI & flag); }
bool HasGroupFlag(uint16 flag) const { return (groupAI & flag); }
};
typedef std::unordered_map<ObjectGuid::LowType/*memberDBGUID*/, FormationInfo /*formationInfo*/> CreatureGroupInfoType;
@@ -3086,7 +3086,7 @@ bool GameObject::IsUpdateNeeded()
if (GetMap()->isCellMarked(GetCurrentCell().GetCellCoord().GetId()))
return true;
if (IsVisibilityOverridden())
if (!GetObjectVisibilityContainer().GetVisiblePlayersMap().empty())
return true;
if (IsTransport())
@@ -156,8 +156,8 @@ public:
void SaveToDB(bool saveAddon = false);
void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool saveAddon = false);
bool LoadFromDB(ObjectGuid::LowType guid, Map* map) { return LoadGameObjectFromDB(guid, map, false); }
bool LoadGameObjectFromDB(ObjectGuid::LowType guid, Map* map, bool addToMap = true);
virtual bool LoadFromDB(ObjectGuid::LowType guid, Map* map) { return LoadGameObjectFromDB(guid, map, false); }
virtual bool LoadGameObjectFromDB(ObjectGuid::LowType guid, Map* map, bool addToMap = true);
void DeleteFromDB();
void SetOwnerGUID(ObjectGuid owner)
+7 -1
View File
@@ -1696,7 +1696,7 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
if (this == obj)
return true;
if (obj->IsNeverVisible() || CanNeverSee(obj))
if (CanNeverSee(obj))
return false;
if (obj->IsAlwaysVisibleFor(this) || CanAlwaysSee(obj))
@@ -1840,6 +1840,12 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
bool WorldObject::CanNeverSee(WorldObject const* obj) const
{
if (!IsInWorld())
return true;
if (obj->IsNeverVisible())
return true;
if (IsCreature() && obj->IsCreature())
return GetMap() != obj->GetMap() || (!InSamePhase(obj) && ToUnit()->GetVehicleBase() != obj && this != obj->ToUnit()->GetVehicleBase());
return GetMap() != obj->GetMap() || !InSamePhase(obj);
@@ -66,6 +66,10 @@ void ObjectVisibilityContainer::LinkWorldObjectVisibility(WorldObject* worldObje
if (worldObject == _selfObject)
return;
// Transports are special and should not be added to our visibility map
if (worldObject->IsGameObject() && worldObject->ToGameObject()->IsTransport())
return;
// Only players can link visibility
if (!_visibleWorldObjectsMap)
return;
@@ -4552,6 +4552,9 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
// update visibility
UpdateObjectVisibility();
// recast lost by death auras of any items held in the inventory
CastAllObtainSpells();
sScriptMgr->OnPlayerResurrect(this, restore_percent, applySickness);
if (!applySickness)
@@ -6019,6 +6022,7 @@ void Player::RewardReputation(Unit* victim)
if (Rep->RepFaction1 && (!Rep->TeamDependent || teamId == TEAM_ALLIANCE))
{
float donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->GetLevel(), static_cast<float>(Rep->RepValue1), ChampioningFaction ? ChampioningFaction : Rep->RepFaction1);
sScriptMgr->OnPlayerGiveReputation(this, Rep->RepFaction1, donerep1, REPUTATION_SOURCE_KILL);
FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction1);
if (factionEntry1)
@@ -6030,6 +6034,7 @@ void Player::RewardReputation(Unit* victim)
if (Rep->RepFaction2 && (!Rep->TeamDependent || teamId == TEAM_HORDE))
{
float donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->GetLevel(), static_cast<float>(Rep->RepValue2), ChampioningFaction ? ChampioningFaction : Rep->RepFaction2);
sScriptMgr->OnPlayerGiveReputation(this, Rep->RepFaction2, donerep2, REPUTATION_SOURCE_KILL);
FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction2);
if (factionEntry2)
@@ -6069,22 +6074,27 @@ void Player::RewardReputation(Quest const* quest)
if (quest->IsDaily())
{
rep = CalculateReputationGain(REPUTATION_SOURCE_DAILY_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], false);
sScriptMgr->OnPlayerGiveReputation(this, quest->RewardFactionId[i], rep, REPUTATION_SOURCE_DAILY_QUEST);
}
else if (quest->IsWeekly())
{
rep = CalculateReputationGain(REPUTATION_SOURCE_WEEKLY_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], false);
sScriptMgr->OnPlayerGiveReputation(this, quest->RewardFactionId[i], rep, REPUTATION_SOURCE_WEEKLY_QUEST);
}
else if (quest->IsMonthly())
{
rep = CalculateReputationGain(REPUTATION_SOURCE_MONTHLY_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], false);
sScriptMgr->OnPlayerGiveReputation(this, quest->RewardFactionId[i], rep, REPUTATION_SOURCE_MONTHLY_QUEST);
}
else if (quest->IsRepeatable())
{
rep = CalculateReputationGain(REPUTATION_SOURCE_REPEATABLE_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], false);
sScriptMgr->OnPlayerGiveReputation(this, quest->RewardFactionId[i], rep, REPUTATION_SOURCE_REPEATABLE_QUEST);
}
else
{
rep = CalculateReputationGain(REPUTATION_SOURCE_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], false);
sScriptMgr->OnPlayerGiveReputation(this, quest->RewardFactionId[i], rep, REPUTATION_SOURCE_QUEST);
}
if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i]))
@@ -7028,6 +7038,46 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
UpdateDamagePhysical(WeaponAttackType(attType));
}
void Player::CastAllObtainSpells()
{
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; ++slot)
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
ApplyItemObtainSpells(item, true);
for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
{
Bag* bag = GetBagByPos(i);
if (!bag)
continue;
for (uint32 slot = 0; slot < bag->GetBagSize(); ++slot)
if (Item* item = bag->GetItemByPos(slot))
ApplyItemObtainSpells(item, true);
}
}
void Player::ApplyItemObtainSpells(Item* item, bool apply)
{
ItemTemplate const* itemTemplate = item->GetTemplate();
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if (itemTemplate->Spells[i].SpellTrigger != ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) // On obtain trigger
continue;
int32 const spellId = itemTemplate->Spells[i].SpellId;
if (spellId <= 0)
continue;
if (apply)
{
if (!HasAura(spellId))
CastSpell(this, spellId, true, item);
}
else
RemoveAurasDueToSpell(spellId);
}
}
SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*= BASE_ATTACK*/, uint8 damageIndex /*= 0*/) const
{
if (Item const* weapon = GetWeaponForAttack(attackType, true))
+6 -14
View File
@@ -235,17 +235,6 @@ enum ActionButtonType
ACTION_BUTTON_ITEM = 0x80
};
enum ReputationSource
{
REPUTATION_SOURCE_KILL,
REPUTATION_SOURCE_QUEST,
REPUTATION_SOURCE_DAILY_QUEST,
REPUTATION_SOURCE_WEEKLY_QUEST,
REPUTATION_SOURCE_MONTHLY_QUEST,
REPUTATION_SOURCE_REPEATABLE_QUEST,
REPUTATION_SOURCE_SPELL
};
enum QuestSound
{
QUEST_SOUND_FAILURE = 847
@@ -1682,7 +1671,7 @@ public:
bool RemoveMItem(ObjectGuid::LowType itemLowGuid)
{
return !!mMitems.erase(itemLowGuid);
return mMitems.erase(itemLowGuid);
}
void PetSpellInitialize();
@@ -2208,6 +2197,9 @@ public:
void ResetAllPowers();
void CastAllObtainSpells();
void ApplyItemObtainSpells(Item* item, bool apply);
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const override;
void _ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply);
@@ -2632,8 +2624,8 @@ public:
std::string GetPlayerName();
// Settings
[[nodiscard]] PlayerSetting GetPlayerSetting(std::string const& source, uint8 index);
void UpdatePlayerSetting(std::string const& source, uint8 index, uint32 value);
[[nodiscard]] PlayerSetting GetPlayerSetting(std::string const& source, uint32 index);
void UpdatePlayerSetting(std::string const& source, uint32 index, uint32 value);
void SendSystemMessage(std::string_view msg, bool escapeCharacters = false);
@@ -18,11 +18,95 @@
#include "Player.h"
#include "StringConvert.h"
#include "Tokenize.h"
#include "CharacterDatabase.h"
/*********************************************************/
/*** PLAYER SETTINGS SYSTEM ***/
/*********************************************************/
namespace PlayerSettingsStore
{
// Common helper: parse space-separated data string into PlayerSettingVector
PlayerSettingVector ParseSettingsData(std::string const& data)
{
PlayerSettingVector result;
std::vector<std::string_view> tokens = Acore::Tokenize(data, ' ', false);
result.reserve(tokens.size());
for (auto const& token : tokens)
{
if (token.empty())
continue;
if (auto parsed = Acore::StringTo<uint32>(token))
result.emplace_back(*parsed);
}
return result;
}
// Common helper: serialize PlayerSettingVector to space-separated string
std::string SerializeSettingsData(PlayerSettingVector const& settings)
{
if (settings.empty())
return "";
std::ostringstream data;
data << settings[0].value;
for (size_t i = 1; i < settings.size(); ++i)
data << ' ' << settings[i].value;
return data.str();
}
// helper: load a single source row for a player and parse to vector
static PlayerSettingVector LoadPlayerSettings(uint32 playerLowGuid, std::string const& source)
{
PlayerSettingVector result;
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_SETTINGS);
stmt->SetData(0, playerLowGuid);
PreparedQueryResult dbRes = CharacterDatabase.Query(stmt);
if (!dbRes)
return result;
do
{
Field* fields = dbRes->Fetch();
std::string rowSource = fields[0].Get<std::string>();
if (rowSource != source)
continue;
std::string data = fields[1].Get<std::string>();
return ParseSettingsData(data);
} while (dbRes->NextRow());
return result;
}
void UpdateSetting(uint32 playerLowGuid, std::string const& source, uint32 index, uint32 value)
{
if (!sWorld->getBoolConfig(CONFIG_PLAYER_SETTINGS_ENABLED))
return;
PlayerSettingVector settings = LoadPlayerSettings(playerLowGuid, source);
size_t const requiredSize = static_cast<size_t>(index) + 1;
if (settings.size() < requiredSize)
settings.resize(requiredSize); // zero-initialized PlayerSetting::value
settings[index].value = value;
CharacterDatabasePreparedStatement* stmt = PlayerSettingsStore::PrepareReplaceStatement(playerLowGuid, source, settings);
CharacterDatabase.Execute(stmt);
}
}
// Implementation of PrepareReplaceStatement
CharacterDatabasePreparedStatement* PlayerSettingsStore::PrepareReplaceStatement(uint32 playerLowGuid, std::string const& source, PlayerSettingVector const& settings)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_SETTINGS);
stmt->SetData(0, playerLowGuid);
stmt->SetData(1, source);
stmt->SetData(2, SerializeSettingsData(settings));
return stmt;
}
void Player::_LoadCharacterSettings(PreparedQueryResult result)
{
m_charSettingsMap.clear();
@@ -39,27 +123,13 @@ void Player::_LoadCharacterSettings(PreparedQueryResult result)
std::string source = fields[0].Get<std::string>();
std::string data = fields[1].Get<std::string>();
std::vector<std::string_view> tokens = Acore::Tokenize(data, ' ', false);
PlayerSettingVector settings;
settings.reserve(tokens.size()); // reserve capacity but don't resize
for (auto const& token : tokens)
{
if (token.empty())
continue;
// Try to parse the value safely
if (auto parsed = Acore::StringTo<uint32>(token))
settings.emplace_back(*parsed);
}
PlayerSettingVector settings = PlayerSettingsStore::ParseSettingsData(data);
m_charSettingsMap.emplace(std::move(source), std::move(settings));
} while (result->NextRow());
}
PlayerSetting Player::GetPlayerSetting(std::string const& source, uint8 index)
PlayerSetting Player::GetPlayerSetting(std::string const& source, uint32 index)
{
auto it = m_charSettingsMap.find(source);
if (it == m_charSettingsMap.end() || static_cast<size_t>(index) >= it->second.size())
@@ -81,21 +151,12 @@ void Player::_SavePlayerSettings(CharacterDatabaseTransaction trans)
if (settings.empty())
continue;
std::ostringstream data;
data << settings[0].value;
for (size_t i = 1; i < settings.size(); ++i)
data << ' ' << settings[i].value;
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_SETTINGS);
stmt->SetData(0, GetGUID().GetCounter());
stmt->SetData(1, source);
stmt->SetData(2, data.str());
CharacterDatabasePreparedStatement* stmt = PlayerSettingsStore::PrepareReplaceStatement(GetGUID().GetCounter(), source, settings);
trans->Append(stmt);
}
}
void Player::UpdatePlayerSetting(std::string const& source, uint8 index, uint32 value)
void Player::UpdatePlayerSetting(std::string const& source, uint32 index, uint32 value)
{
auto it = m_charSettingsMap.find(source);
size_t const requiredSize = static_cast<size_t>(index) + 1;
@@ -17,6 +17,7 @@
#ifndef _PLAYER_SETTINGS_H
#define _PLAYER_SETTINGS_H
#include "DatabaseEnvFwd.h"
class Player;
@@ -51,4 +52,18 @@ struct PlayerSetting
typedef std::vector<PlayerSetting> PlayerSettingVector;
typedef std::map<std::string, PlayerSettingVector> PlayerSettingMap;
// Standalone API: update a player's setting directly on DB by GUID (low part) without requiring a Player instance
namespace PlayerSettingsStore
{
// Update a single setting value for any player by GUID (works for online or offline players).
// This reads the existing "source" row from character_settings, adjusts the index, and REPLACE's it back.
void UpdateSetting(uint32 playerLowGuid, std::string const& source, uint32 index, uint32 value);
// Common helpers for parsing and serializing settings data
PlayerSettingVector ParseSettingsData(std::string const& data);
std::string SerializeSettingsData(PlayerSettingVector const& settings);
// Prepare a REPLACE statement populated with given settings data. Caller may execute or append to a transaction.
CharacterDatabasePreparedStatement* PrepareReplaceStatement(uint32 playerLowGuid, std::string const& source, PlayerSettingVector const& settings);
}
#endif
@@ -2577,8 +2577,6 @@ Item* Player::StoreItem(ItemPosCountVec const& dest, Item* pItem, bool update)
return nullptr;
Item* lastItem = pItem;
ItemTemplate const* proto = pItem->GetTemplate();
for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end();)
{
uint16 pos = itr->pos;
@@ -2595,13 +2593,6 @@ Item* Player::StoreItem(ItemPosCountVec const& dest, Item* pItem, bool update)
lastItem = _StoreItem(pos, pItem, count, true, update);
}
// cast after item storing - some checks in checkcast requires item to be present!!
if (lastItem)
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
if (proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE && proto->Spells[i].SpellId > 0) // On obtain trigger
if (!HasAura(proto->Spells[i].SpellId))
CastSpell(this, proto->Spells[i].SpellId, true, lastItem);
return lastItem;
}
@@ -2664,6 +2655,9 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool
AddEnchantmentDurations(pItem);
AddItemDurations(pItem);
if (bag == INVENTORY_SLOT_BAG_0 || (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END))
ApplyItemObtainSpells(pItem, true);
return pItem;
}
else
@@ -2700,6 +2694,9 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool
pItem2->SetState(ITEM_CHANGED, this);
if (bag == INVENTORY_SLOT_BAG_0 || (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END))
ApplyItemObtainSpells(pItem2, true);
return pItem2;
}
}
@@ -3046,10 +3043,7 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
pItem->ClearSoulboundTradeable(this);
RemoveTradeableItem(pItem);
ItemTemplate const* proto = pItem->GetTemplate();
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
if (proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE && proto->Spells[i].SpellId > 0) // On obtain trigger
RemoveAurasDueToSpell(proto->Spells[i].SpellId);
ApplyItemObtainSpells(pItem, false);
ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount());
@@ -3102,8 +3096,9 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
pBag->RemoveItem(slot, update);
// Xinef: item is removed, remove loot from storage if any
if (proto->HasFlag(ITEM_FLAG_HAS_LOOT))
sLootItemStorage->RemoveStoredLoot(pItem->GetGUID());
if (ItemTemplate const* proto = pItem->GetTemplate())
if (proto->HasFlag(ITEM_FLAG_HAS_LOOT))
sLootItemStorage->RemoveStoredLoot(pItem->GetGUID());
if (IsInWorld() && update)
{
@@ -1646,10 +1646,7 @@ template <>
inline void UpdateVisibilityOf_helper(Player* player, GameObject* target,
std::vector<Unit*>& /*v*/)
{
// @HACK: This is to prevent objects like deeprun tram from disappearing
// when player moves far from its spawn point while riding it
if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
player->GetObjectVisibilityContainer().LinkWorldObjectVisibility(target);
player->GetObjectVisibilityContainer().LinkWorldObjectVisibility(target);
}
template <>
@@ -607,12 +607,12 @@ void MotionTransport::DelayedTeleportTransport()
}
Map* newMap = sMapMgr->CreateBaseMap(newMapId);
GetMap()->RemoveFromMap<MotionTransport>(this, false);
GetMap()->RemoveFromMap<Transport>(this, false);
newMap->LoadGrid(x, y); // xinef: load before adding passengers to new map
SetMap(newMap);
Relocate(x, y, z, o);
GetMap()->AddToMap<MotionTransport>(this);
GetMap()->AddToMap<Transport>(this);
LoadStaticPassengers();
}
@@ -690,6 +690,40 @@ StaticTransport::~StaticTransport()
ASSERT(_passengers.empty());
}
bool StaticTransport::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap)
{
GameObjectData const* data = sObjectMgr->GetGameObjectData(spawnId);
if (!data)
{
LOG_ERROR("sql.sql", "Gameobject (GUID: {}) not found in table `gameobject`, can't load. ", spawnId);
return false;
}
uint32 entry = data->id;
//uint32 map_id = data->mapid; // already used before call
uint32 phaseMask = data->phaseMask;
float x = data->posX;
float y = data->posY;
float z = data->posZ;
float ang = data->orientation;
uint32 animprogress = data->animprogress;
GOState go_state = data->go_state;
uint32 artKit = data->artKit;
m_goData = data;
m_spawnId = spawnId;
if (!Create(map->GenerateLowGuid<HighGuid::Transport>(), entry, map, phaseMask, x, y, z, ang, data->rotation, animprogress, go_state, artKit))
return false;
if (addToMap && !GetMap()->AddToMap<Transport>(this))
return false;
return true;
}
bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, G3D::Quat const& rotation, uint32 animprogress, GOState go_state, uint32 artKit)
{
ASSERT(map);
@@ -794,7 +828,6 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m
LastUsedScriptID = GetGOInfo()->ScriptId;
AIM_Initialize();
this->setActive(true);
return true;
}
@@ -929,7 +962,9 @@ void StaticTransport::UpdatePosition(float x, float y, float z, float o)
if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case
GetMap()->LoadGrid(x, y);
GetMap()->GameObjectRelocation(this, x, y, z, o); // this also relocates the model
Relocate(x, y, z, o);
UpdateModelPosition();
UpdatePassengerPositions();
}
@@ -38,6 +38,8 @@ public:
virtual void RemovePassenger(WorldObject* passenger, bool withAll = false) = 0;
PassengerSet const& GetPassengers() const { return _passengers; }
virtual void DelayedUpdate(uint32 /*diff*/) {}
uint32 GetPathProgress() const { return GetGOValue()->Transport.PathProgress; }
void SetPathProgress(uint32 val) { m_goValue.Transport.PathProgress = val; }
@@ -57,7 +59,7 @@ public:
void BuildUpdate(UpdateDataMapType& data_map) override;
void Update(uint32 diff) override;
void DelayedUpdate(uint32 diff);
void DelayedUpdate(uint32 diff) override;
void UpdatePosition(float x, float y, float z, float o);
void AddPassenger(WorldObject* passenger, bool withAll = false) override;
@@ -115,6 +117,8 @@ public:
StaticTransport();
~StaticTransport() override;
bool LoadFromDB(ObjectGuid::LowType guid, Map* map) override { return LoadGameObjectFromDB(guid, map, false); }
bool LoadGameObjectFromDB(ObjectGuid::LowType guid, Map* map, bool addToMap = true) override;
bool Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, G3D::Quat const& rotation, uint32 animprogress, GOState go_state, uint32 artKit = 0) override;
void CleanupsBeforeDelete(bool finalCleanup = true) override;
void BuildUpdate(UpdateDataMapType& data_map) override;
+12 -2
View File
@@ -53,6 +53,7 @@
#include "Player.h"
#include "ReputationMgr.h"
#include "ScriptMgr.h"
#include "SmartAI.h"
#include "Spell.h"
#include "SpellAuraEffects.h"
#include "SpellAuras.h"
@@ -4109,8 +4110,8 @@ void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool wi
//LOG_DEBUG("entities.unit", "Interrupt spell for unit {}.", GetEntry());
Spell* spell = m_currentSpells[spellType];
if (spell
&& (withDelayed || spell->getState() != SPELL_STATE_DELAYED)
&& (withInstant || spell->GetCastTime() > 0 || spell->getState() == SPELL_STATE_CASTING)) // xinef: or spell is in casting state (channeled spells only)
&& (withDelayed || spell->getState() != SPELL_STATE_DELAYED)
&& (withInstant || spell->GetCastTime() > 0 || spell->getState() == SPELL_STATE_CASTING)) // xinef: or spell is in casting state (channeled spells only)
{
// for example, do not let self-stun aura interrupt itself
if (!spell->IsInterruptable())
@@ -4128,6 +4129,15 @@ void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool wi
m_currentSpells[spellType] = nullptr;
spell->SetReferencedFromCurrent(false);
}
// SAI creatures only
// Start chasing victim if they are spell casters (at least one SMC spell) if interrupted/silenced.
if (IsCreature())
{
if (SmartAI* ai = dynamic_cast<SmartAI*>(ToCreature()->AI()))
if (ai->CanChaseOnInterrupt())
ai->SetCombatMove(true);
}
}
}
+19 -6
View File
@@ -64,15 +64,28 @@ 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))
if (data && sObjectMgr->IsGameObjectStaticTransport(data->id))
{
delete obj;
continue;
}
StaticTransport* transport = new StaticTransport();
AddObjectHelper<GameObject>(map, obj);
// Special case for static transports - we are loaded via grids
// but we do not want to actually be stored in the grid
if (!transport->LoadGameObjectFromDB(guid, map, true))
delete transport;
}
else
{
GameObject* obj = new GameObject();
if (!obj->LoadFromDB(guid, map))
{
delete obj;
continue;
}
AddObjectHelper<GameObject>(map, obj);
}
}
}
+11
View File
@@ -28,6 +28,7 @@
#include "LFGMgr.h"
#include "Log.h"
#include "MapMgr.h"
#include "MiscPackets.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Player.h"
@@ -2059,6 +2060,16 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
return GroupJoinBattlegroundResult(bgTemplate->GetBgTypeID());
}
void Group::DoMinimapPing(ObjectGuid sourceGuid, float mapX, float mapY)
{
WorldPackets::Misc::MinimapPing minimapPing;
minimapPing.SourceGuid = sourceGuid;
minimapPing.MapX = mapX;
minimapPing.MapY = mapY;
BroadcastPacket(minimapPing.Write(), true, -1, sourceGuid);
}
//===================================================
//============== Roll ===============================
//===================================================
+2
View File
@@ -255,6 +255,8 @@ public:
void SetBattlefieldGroup(Battlefield* bf);
GroupJoinBattlegroundResult CanJoinBattlegroundQueue(Battleground const* bgTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot);
void DoMinimapPing(ObjectGuid sourceGuid, float mapX, float mapY);
void ChangeMembersGroup(ObjectGuid guid, uint8 group);
void SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid);
void SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags flag);
@@ -1175,6 +1175,10 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar)
pCurrChar->GetMap()->SendInitTransports(pCurrChar);
pCurrChar->GetMap()->SendInitSelf(pCurrChar);
pCurrChar->GetMap()->SendZoneDynamicInfo(pCurrChar);
// If we are logging into an existing player, simply clear visibility references
// so player will receive a fresh list of new objects on the next vis update.
pCurrChar->GetObjectVisibilityContainer().CleanVisibilityReferences();
pCurrChar->UpdateObjectVisibility(false);
pCurrChar->CleanupChannels();
+8 -16
View File
@@ -22,6 +22,7 @@
#include "LFGMgr.h"
#include "Language.h"
#include "Log.h"
#include "MapMgr.h"
#include "MiscPackets.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
@@ -522,24 +523,17 @@ void WorldSession::HandleLootRoll(WorldPacket& recvData)
}
}
void WorldSession::HandleMinimapPingOpcode(WorldPacket& recvData)
void WorldSession::HandleMinimapPingOpcode(WorldPackets::Misc::MinimapPingClient& packet)
{
if (!GetPlayer()->GetGroup())
if (!sMapMgr->IsValidMapCoord(GetPlayer()->GetMap()->GetId(), packet.MapX, packet.MapY))
return;
float x, y;
recvData >> x;
recvData >> y;
Group* group = GetPlayer()->GetGroup();
/** error handling **/
/********************/
if (!group)
return;
// everything's fine, do it
WorldPacket data(MSG_MINIMAP_PING, (8 + 4 + 4));
data << GetPlayer()->GetGUID();
data << float(x);
data << float(y);
GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID());
group->DoMinimapPing(GetPlayer()->GetGUID(), packet.MapX, packet.MapY);
}
void WorldSession::HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& packet)
@@ -549,10 +543,8 @@ void WorldSession::HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient&
maximum = packet.Max;
/** error handling **/
if (minimum > maximum || maximum > 10000) // < 32768 for urand call
{
if (minimum > maximum || maximum > sWorld->getIntConfig(CONFIG_RANDOM_ROLL_MAXIMUM))
return;
}
GetPlayer()->DoRandomRoll(minimum, maximum);
}
+25 -34
View File
@@ -24,6 +24,7 @@
#include "Opcodes.h"
#include "Pet.h"
#include "Player.h"
#include "QueryPackets.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
@@ -32,62 +33,55 @@ void WorldSession::SendNameQueryOpcode(ObjectGuid guid)
{
CharacterCacheEntry const* playerData = sCharacterCache->GetCharacterCacheByGuid(guid);
WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8 + 1 + 1 + 1 + 1 + 1 + 10));
data << guid.WriteAsPacked();
WorldPackets::Query::NameQueryResponse nameQueryResponse;
nameQueryResponse.Guid = guid.WriteAsPacked();
if (!playerData)
{
data << uint8(1); // name unknown
SendPacket(&data);
nameQueryResponse.NameUnknown = true;
SendPacket(nameQueryResponse.Write());
return;
}
Player* player = ObjectAccessor::FindConnectedPlayer(guid);
data << uint8(0); // name known
data << playerData->Name; // played name
data << uint8(0); // realm name - only set for cross realm interaction (such as Battlegrounds)
data << uint8(player ? player->getRace() : playerData->Race);
data << uint8(playerData->Sex);
data << uint8(playerData->Class);
nameQueryResponse.NameUnknown = false;
nameQueryResponse.Name = playerData->Name;
nameQueryResponse.Race = player ? player->getRace() : playerData->Race;
nameQueryResponse.Sex = player ? player->getGender() : playerData->Sex;
nameQueryResponse.Class = player ? player->getClass() : playerData->Class;
// pussywizard: optimization
/*Player* player = ObjectAccessor::FindConnectedPlayer(guid);
if (DeclinedName const* names = (player ? player->GetDeclinedNames() : nullptr))
{
data << uint8(1); // Name is declined
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
data << names->name[i];
nameQueryResponse.Declined = true;
nameQueryResponse.DeclinedNames = *names;
}
else*/
data << uint8(0); // Name is not declined
else
nameQueryResponse.Declined = false;
SendPacket(&data);
SendPacket(nameQueryResponse.Write());
}
void WorldSession::HandleNameQueryOpcode(WorldPacket& recvData)
void WorldSession::HandleNameQueryOpcode(WorldPackets::Query::NameQuery& packet)
{
ObjectGuid guid;
recvData >> guid;
// This is disable by default to prevent lots of console spam
// LOG_INFO("network.opcode", "HandleNameQueryOpcode {}", guid);
SendNameQueryOpcode(guid);
SendNameQueryOpcode(packet.Guid);
}
void WorldSession::HandleQueryTimeOpcode(WorldPacket& /*recvData*/)
void WorldSession::HandleTimeQueryOpcode(WorldPackets::Query::TimeQuery& /*packet*/)
{
SendQueryTimeResponse();
SendTimeQueryResponse();
}
void WorldSession::SendQueryTimeResponse()
void WorldSession::SendTimeQueryResponse()
{
auto timeResponse = sWorld->GetNextDailyQuestsResetTime() - GameTime::GetGameTime();
WorldPacket data(SMSG_QUERY_TIME_RESPONSE, 4 + 4);
data << uint32(GameTime::GetGameTime().count());
data << uint32(timeResponse.count());
SendPacket(&data);
WorldPackets::Query::TimeQueryResponse timeQueryResponse;
timeQueryResponse.ServerTime = GameTime::GetGameTime().count();
timeQueryResponse.TimeResponse = timeResponse.count();
SendPacket(timeQueryResponse.Write());
}
/// Only _static_ data is sent in this packet !!!
@@ -402,13 +396,10 @@ void WorldSession::HandlePageTextQueryOpcode(WorldPacket& recvData)
}
}
void WorldSession::HandleCorpseMapPositionQuery(WorldPacket& recvData)
void WorldSession::HandleCorpseMapPositionQuery(WorldPackets::Query::CorpseMapPositionQuery& /*packet*/)
{
LOG_DEBUG("network", "WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY");
uint32 unk;
recvData >> unk;
WorldPacket data(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, 4 + 4 + 4 + 4);
data << float(0);
data << float(0);
+1 -1
View File
@@ -172,7 +172,7 @@ void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket& /*recv_data*/)
void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket& /*recv_data*/)
{
SendQueryTimeResponse();
SendTimeQueryResponse();
if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID()))
{
+20 -33
View File
@@ -345,7 +345,7 @@ bool Map::AddToMap(T* obj, bool checkTransport)
}
template<>
bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/)
bool Map::AddToMap(Transport* obj, bool /*checkTransport*/)
{
//TODO: Needs clean up. An object should not be added to map twice.
if (obj->IsInWorld())
@@ -360,26 +360,22 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/)
}
Cell cell(cellCoord);
if (obj->isActiveObject())
EnsureGridLoaded(cell);
EnsureGridLoaded(cell);
obj->AddToWorld();
_transports.insert(obj);
// Broadcast creation to players
if (!GetPlayers().IsEmpty())
for (Map::PlayerList::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
{
for (Map::PlayerList::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
if (itr->GetSource()->GetTransport() != obj)
{
if (itr->GetSource()->GetTransport() != obj)
{
UpdateData data;
obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource());
WorldPacket packet;
data.BuildPacket(packet);
itr->GetSource()->SendDirectMessage(&packet);
}
UpdateData data;
obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource());
WorldPacket packet;
data.BuildPacket(packet);
itr->GetSource()->SendDirectMessage(&packet);
}
}
@@ -667,7 +663,7 @@ void Map::RemoveFromMap(T* obj, bool remove)
}
template<>
void Map::RemoveFromMap(MotionTransport* obj, bool remove)
void Map::RemoveFromMap(Transport* obj, bool remove)
{
obj->RemoveFromWorld();
@@ -697,8 +693,6 @@ void Map::RemoveFromMap(MotionTransport* obj, bool remove)
obj->ResetMap();
// Transports are never actually deleted, but it *should* be safe to clear
// from update list when removing from world
RemoveObjectFromMapUpdateList(obj);
if (remove)
@@ -966,11 +960,10 @@ void Map::UnloadAll()
for (TransportsContainer::iterator itr = _transports.begin(); itr != _transports.end();)
{
MotionTransport* transport = *itr;
Transport* transport = *itr;
++itr;
transport->RemoveFromWorld();
delete transport;
RemoveFromMap<Transport>(transport, true);
}
_transports.clear();
@@ -1589,6 +1582,9 @@ void Map::SendInitSelf(Player* player)
void Map::SendInitTransports(Player* player)
{
if (_transports.empty())
return;
// Hack to send out transports
UpdateData transData;
for (TransportsContainer::const_iterator itr = _transports.begin(); itr != _transports.end(); ++itr)
@@ -1605,24 +1601,15 @@ void Map::SendInitTransports(Player* player)
void Map::SendRemoveTransports(Player* player)
{
if (_transports.empty())
return;
// Hack to send out transports
UpdateData transData;
for (TransportsContainer::const_iterator itr = _transports.begin(); itr != _transports.end(); ++itr)
if (*itr != player->GetTransport())
(*itr)->BuildOutOfRangeUpdateBlock(&transData);
// pussywizard: remove static transports from client
/*for (GuidUnorderedSet::const_iterator it = player->m_clientGUIDs.begin(); it != player->m_clientGUIDs.end(); )
{
if ((*it).IsTransport())
{
transData.AddOutOfRangeGUID(*it);
it = player->m_clientGUIDs.erase(it);
}
else
++it;
}*/
if (!transData.HasData())
return;
@@ -1699,7 +1686,7 @@ void Map::DelayedUpdate(const uint32 t_diff)
{
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
{
MotionTransport* transport = *_transportsUpdateIter;
Transport* transport = *_transportsUpdateIter;
++_transportsUpdateIter;
if (!transport->IsInWorld())
@@ -1744,7 +1731,7 @@ void Map::RemoveAllObjectsInRemoveList()
RemoveFromMap((DynamicObject*)obj, true);
break;
case TYPEID_GAMEOBJECT:
if (MotionTransport* transport = obj->ToGameObject()->ToMotionTransport())
if (Transport* transport = obj->ToGameObject()->ToTransport())
RemoveFromMap(transport, true);
else
RemoveFromMap(obj->ToGameObject(), true);
+2 -3
View File
@@ -146,7 +146,7 @@ struct ZoneDynamicInfo
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap;
typedef std::set<MotionTransport*> TransportsContainer;
typedef std::unordered_set<Transport*> TransportsContainer;
enum EncounterCreditType : uint8
{
@@ -479,7 +479,7 @@ public:
_updateObjects.erase(obj);
}
size_t GetUpdateObjectsCount() const { return _updateObjects.size(); }
size_t GetUpdatableObjectsCount() const { return _updatableObjectList.size(); }
virtual std::string GetDebugInfo() const;
@@ -535,7 +535,6 @@ protected:
MapRefMgr m_mapRefMgr;
MapRefMgr::iterator m_mapRefIter;
// Objects that must update even in inactive grids without activating them
TransportsContainer _transports;
TransportsContainer::iterator _transportsUpdateIter;
+1 -3
View File
@@ -412,10 +412,8 @@ MotionTransport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType
if (map && map->IsDungeon())
trans->m_zoneScript = map->ToInstanceMap()->GetInstanceScript();
// xinef: transports are active so passengers can be relocated (grids must be loaded)
trans->setActive(true);
HashMapHolder<MotionTransport>::Insert(trans);
trans->GetMap()->AddToMap<MotionTransport>(trans);
trans->GetMap()->AddToMap<Transport>(trans);
return trans;
}
@@ -139,6 +139,11 @@ void ScriptMgr::OnPlayerReputationRankChange(Player* player, uint32 factionID, R
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_REPUTATION_RANK_CHANGE, script->OnPlayerReputationRankChange(player, factionID, newRank, oldRank, increased));
}
void ScriptMgr::OnPlayerGiveReputation(Player* player, int32 factionID, float& amount, ReputationSource repSource)
{
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_GIVE_REPUTATION, script->OnPlayerGiveReputation(player, factionID, amount, repSource));
}
void ScriptMgr::OnPlayerLearnSpell(Player* player, uint32 spellID)
{
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_LEARN_SPELL, script->OnPlayerLearnSpell(player, spellID));
@@ -211,6 +211,7 @@ enum PlayerHook
PLAYERHOOK_CAN_RESURRECT,
PLAYERHOOK_ON_CAN_GIVE_LEVEL,
PLAYERHOOK_ON_SEND_LIST_INVENTORY,
PLAYERHOOK_ON_GIVE_REPUTATION,
PLAYERHOOK_END
};
@@ -285,6 +286,9 @@ public:
// Called when a player's reputation rank changes (before it is actually changed)
virtual void OnPlayerReputationRankChange(Player* /*player*/, uint32 /*factionID*/, ReputationRank /*newRank*/, ReputationRank /*olRank*/, bool /*increased*/) { }
// Called when a player gains Reputation (before anything is given)
virtual void OnPlayerGiveReputation(Player* /*player*/, int32 /*factionID*/, float& /*amount*/, ReputationSource /*repSource*/) { }
// Called when a player learned new spell
virtual void OnPlayerLearnSpell(Player* /*player*/, uint32 /*spellID*/) {}
+1
View File
@@ -334,6 +334,7 @@ public: /* PlayerScript */
void OnPlayerGiveXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource);
bool OnPlayerReputationChange(Player* player, uint32 factionID, int32& standing, bool incremental);
void OnPlayerReputationRankChange(Player* player, uint32 factionID, ReputationRank newRank, ReputationRank oldRank, bool increased);
void OnPlayerGiveReputation(Player* player, int32 factionID, float& amount, ReputationSource repSource);
void OnPlayerLearnSpell(Player* player, uint32 spellID);
void OnPlayerForgotSpell(Player* player, uint32 spellID);
void OnPlayerDuelRequest(Player* target, Player* challenger);
@@ -27,6 +27,7 @@
#include "LFGPackets.h"
#include "MiscPackets.h"
#include "PetPackets.h"
#include "QueryPackets.h"
#include "TotemPackets.h"
#include "WorldStatePackets.h"
@@ -67,6 +67,21 @@ WorldPacket const* WorldPackets::Misc::Playsound::Write()
return &_worldPacket;
}
void WorldPackets::Misc::MinimapPingClient::Read()
{
_worldPacket >> MapX;
_worldPacket >> MapY;
}
WorldPacket const* WorldPackets::Misc::MinimapPing::Write()
{
_worldPacket << SourceGuid;
_worldPacket << float(MapX);
_worldPacket << float(MapY);
return &_worldPacket;
}
void WorldPackets::Misc::RandomRollClient::Read()
{
_worldPacket >> Min;
@@ -93,6 +93,29 @@ namespace WorldPackets
uint32 SoundKitID = 0;
};
class MinimapPingClient final : public ClientPacket
{
public:
MinimapPingClient(WorldPacket&& packet) : ClientPacket(MSG_MINIMAP_PING, std::move(packet)) {}
void Read() override;
float MapX = 0.0f; // Raw position coordinates
float MapY = 0.0f;
};
class MinimapPing final : public ServerPacket
{
public:
MinimapPing() : ServerPacket(MSG_MINIMAP_PING, 8 + 4 + 4) { }
WorldPacket const* Write() override;
ObjectGuid SourceGuid;
float MapX = 0.0f;
float MapY = 0.0f;
};
class RandomRollClient final : public ClientPacket
{
public:
@@ -0,0 +1,58 @@
/*
* 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 "QueryPackets.h"
void WorldPackets::Query::NameQuery::Read()
{
_worldPacket >> Guid;
}
WorldPacket const* WorldPackets::Query::NameQueryResponse::Write()
{
_worldPacket << Guid;
_worldPacket << NameUnknown;
if (NameUnknown)
return &_worldPacket;
_worldPacket << Name;
_worldPacket << RealmName;
_worldPacket << Race;
_worldPacket << Sex;
_worldPacket << Class;
_worldPacket << Declined;
if (Declined)
{
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
_worldPacket << DeclinedNames.name[i];
}
return &_worldPacket;
}
WorldPacket const* WorldPackets::Query::TimeQueryResponse::Write()
{
_worldPacket << ServerTime;
_worldPacket << TimeResponse;
return &_worldPacket;
}
void WorldPackets::Query::CorpseMapPositionQuery::Read()
{
_worldPacket >> unk;
}
@@ -0,0 +1,87 @@
/*
* 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 QueryPackets_h__
#define QueryPackets_h__
#include "Packet.h"
#include "Unit.h"
namespace WorldPackets
{
namespace Query
{
class NameQuery final : public ClientPacket
{
public:
NameQuery(WorldPacket&& packet) : ClientPacket(CMSG_NAME_QUERY, std::move(packet)) {}
void Read() override;
ObjectGuid Guid;
};
class NameQueryResponse final : public ServerPacket
{
public:
NameQueryResponse() : ServerPacket(SMSG_NAME_QUERY_RESPONSE, 8 + 1 + 1 + 1 + 1 + 1 + 10) {}
WorldPacket const* Write() override;
PackedGuid Guid;
uint8 NameUnknown = false;
std::string_view Name;
std::string_view RealmName = ""; // Only set for cross realm interaction (such as Battlegrounds)
uint8 Race = RACE_NONE;
uint8 Sex = GENDER_MALE;
uint8 Class = CLASS_NONE;
uint8 Declined = false;
DeclinedName DeclinedNames;
};
class TimeQuery final : public ClientPacket
{
public:
TimeQuery(WorldPacket&& packet) : ClientPacket(CMSG_QUERY_TIME, std::move(packet)) {}
void Read() override {};
};
class TimeQueryResponse final : public ServerPacket
{
public:
TimeQueryResponse() : ServerPacket(SMSG_QUERY_TIME_RESPONSE, 4 + 4) {}
WorldPacket const* Write() override;
uint32 ServerTime;
uint32 TimeResponse;
};
class CorpseMapPositionQuery final : public ClientPacket
{
public:
CorpseMapPositionQuery(WorldPacket&& packet) : ClientPacket(CMSG_CORPSE_MAP_POSITION_QUERY, std::move(packet)) {}
void Read() override;
uint32 unk;
};
}
}
#endif // QueryPackets_h__
+1 -1
View File
@@ -590,7 +590,7 @@ void OpcodeTable::Initialize()
/*0x1CB*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFICATION, STATUS_NEVER);
/*0x1CC*/ DEFINE_HANDLER(CMSG_PLAYED_TIME, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandlePlayedTime );
/*0x1CD*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYED_TIME, STATUS_NEVER);
/*0x1CE*/ DEFINE_HANDLER(CMSG_QUERY_TIME, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleQueryTimeOpcode );
/*0x1CE*/ DEFINE_HANDLER(CMSG_QUERY_TIME, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleTimeQueryOpcode );
/*0x1CF*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_TIME_RESPONSE, STATUS_NEVER);
/*0x1D0*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOG_XPGAIN, STATUS_NEVER);
/*0x1D1*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_AURACASTLOG, STATUS_NEVER);
+13 -5
View File
@@ -148,6 +148,7 @@ namespace WorldPackets
namespace Misc
{
class MinimapPingClient;
class RandomRollClient;
}
@@ -159,6 +160,13 @@ namespace WorldPackets
class PetSpellAutocast;
class RequestPetInfo;
}
namespace Query
{
class NameQuery;
class TimeQuery;
class CorpseMapPositionQuery;
}
}
enum AccountDataType
@@ -389,7 +397,7 @@ public:
}
void SendSetPhaseShift(uint32 phaseShift);
void SendQueryTimeResponse();
void SendTimeQueryResponse();
void SendAuthResponse(uint8 code, bool shortForm, uint32 queuePos = 0);
void SendClientCacheVersion(uint32 version);
@@ -680,9 +688,9 @@ public: // opcodes handlers
void HandleGameObjectUseOpcode(WorldPacket& recPacket);
void HandleGameobjectReportUse(WorldPacket& recvPacket);
void HandleNameQueryOpcode(WorldPacket& recvPacket);
void HandleNameQueryOpcode(WorldPackets::Query::NameQuery& packet);
void HandleQueryTimeOpcode(WorldPacket& recvPacket);
void HandleTimeQueryOpcode(WorldPackets::Query::TimeQuery& packet);
void HandleCreatureQueryOpcode(WorldPacket& recvPacket);
@@ -882,7 +890,7 @@ public: // opcodes handlers
void HandleReclaimCorpseOpcode(WorldPacket& recvPacket);
void HandleCorpseQueryOpcode(WorldPacket& recvPacket);
void HandleCorpseMapPositionQuery(WorldPacket& recvPacket);
void HandleCorpseMapPositionQuery(WorldPackets::Query::CorpseMapPositionQuery& packet);
void HandleResurrectResponseOpcode(WorldPacket& recvPacket);
void HandleSummonResponseOpcode(WorldPacket& recvData);
@@ -953,7 +961,7 @@ public: // opcodes handlers
void HandleWardenDataOpcode(WorldPacket& recvData);
void HandleWorldTeleportOpcode(WorldPacket& recvData);
void HandleMinimapPingOpcode(WorldPacket& recvData);
void HandleMinimapPingOpcode(WorldPackets::Misc::MinimapPingClient& packet);
void HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& packet);
void HandleFarSightOpcode(WorldPacket& recvData);
void HandleSetDungeonDifficultyOpcode(WorldPacket& recvData);
+2
View File
@@ -492,6 +492,8 @@ void WorldConfig::BuildConfigCache()
SetConfigValue<bool>(CONFIG_LEAVE_GROUP_ON_LOGOUT, "LeaveGroupOnLogout.Enabled", false);
SetConfigValue<uint32>(CONFIG_RANDOM_ROLL_MAXIMUM, "Group.RandomRollMaximum", 1000000);
SetConfigValue<bool>(CONFIG_QUEST_POI_ENABLED, "QuestPOI.Enabled", true);
SetConfigValue<uint32>(CONFIG_CHANGE_FACTION_MAX_MONEY, "ChangeFaction.MaxMoney", 0);
+1
View File
@@ -129,6 +129,7 @@ enum ServerConfigs
CONFIG_ALLOW_JOIN_BG_AND_LFG,
CONFIG_MISS_CHANCE_MULTIPLIER_ONLY_FOR_PLAYERS,
CONFIG_LEAVE_GROUP_ON_LOGOUT,
CONFIG_RANDOM_ROLL_MAXIMUM,
CONFIG_QUEST_POI_ENABLED,
CONFIG_VMAP_BLIZZLIKE_PVP_LOS,
CONFIG_VMAP_BLIZZLIKE_LOS_OPEN_WORLD,