Merge branch 'master' into Playerbot
This commit is contained in:
@@ -23,6 +23,17 @@
|
||||
#include "Unit.h"
|
||||
#include <list>
|
||||
|
||||
#define CAST_AI(a, b) (dynamic_cast<a*>(b))
|
||||
#define ENSURE_AI(a,b) (EnsureAI<a>(b))
|
||||
|
||||
template<class T, class U>
|
||||
T* EnsureAI(U* ai)
|
||||
{
|
||||
T* cast_ai = dynamic_cast<T*>(ai);
|
||||
ASSERT(cast_ai);
|
||||
return cast_ai;
|
||||
}
|
||||
|
||||
class Player;
|
||||
class Quest;
|
||||
class Unit;
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include "InstanceScript.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
#define CAST_AI(a, b) (dynamic_cast<a*>(b))
|
||||
|
||||
typedef std::list<WorldObject*> ObjectList;
|
||||
|
||||
class InstanceScript;
|
||||
|
||||
@@ -962,9 +962,9 @@ uint32 SmartAI::GetData(uint32 /*id*/) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SmartAI::SetData(uint32 id, uint32 value)
|
||||
void SmartAI::SetData(uint32 id, uint32 value, Unit* invoker)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DATA_SET, nullptr, id, value);
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DATA_SET, invoker, id, value);
|
||||
}
|
||||
|
||||
void SmartAI::SetGUID(ObjectGuid /*guid*/, int32 /*id*/)
|
||||
@@ -1232,9 +1232,9 @@ void SmartGameObjectAI::Destroyed(Player* player, uint32 eventId)
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, player, eventId, 0, false, nullptr, me);
|
||||
}
|
||||
|
||||
void SmartGameObjectAI::SetData(uint32 id, uint32 value)
|
||||
void SmartGameObjectAI::SetData(uint32 id, uint32 value, Unit* invoker)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DATA_SET, nullptr, id, value);
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DATA_SET, invoker, id, value);
|
||||
}
|
||||
|
||||
void SmartGameObjectAI::SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker)
|
||||
|
||||
@@ -159,7 +159,8 @@ public:
|
||||
uint32 GetData(uint32 id = 0) const override;
|
||||
|
||||
// Used in scripts to share variables
|
||||
void SetData(uint32 id, uint32 value) override;
|
||||
void SetData(uint32 id, uint32 value) override { SetData(id, value, nullptr); }
|
||||
void SetData(uint32 id, uint32 value, Unit* invoker);
|
||||
|
||||
// Used in scripts to share variables
|
||||
void SetGUID(ObjectGuid guid, int32 id = 0) override;
|
||||
@@ -272,7 +273,8 @@ public:
|
||||
bool QuestAccept(Player* player, Quest const* quest) override;
|
||||
bool QuestReward(Player* player, Quest const* quest, uint32 opt) override;
|
||||
void Destroyed(Player* player, uint32 eventId) override;
|
||||
void SetData(uint32 id, uint32 value) override;
|
||||
void SetData(uint32 id, uint32 value) override { SetData(id, value, nullptr); }
|
||||
void SetData(uint32 id, uint32 value, Unit* invoker);
|
||||
void SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker);
|
||||
void OnGameEvent(bool start, uint16 eventId) override;
|
||||
void OnStateChanged(uint32 state, Unit* unit) override;
|
||||
|
||||
@@ -63,7 +63,46 @@ SmartScript::SmartScript()
|
||||
|
||||
SmartScript::~SmartScript()
|
||||
{
|
||||
}
|
||||
|
||||
bool SmartScript::IsSmart(Creature* c, bool silent) const
|
||||
{
|
||||
if (!c)
|
||||
return false;
|
||||
|
||||
bool smart = true;
|
||||
if (!dynamic_cast<SmartAI*>(c->AI()))
|
||||
smart = false;
|
||||
|
||||
if (!smart && !silent)
|
||||
LOG_ERROR("sql.sql", "SmartScript: Action target Creature(entry: {}) is not using SmartAI, action skipped to prevent crash.", c ? c->GetEntry() : (me ? me->GetEntry() : 0));
|
||||
|
||||
return smart;
|
||||
}
|
||||
|
||||
bool SmartScript::IsSmart(GameObject* g, bool silent) const
|
||||
{
|
||||
if (!g)
|
||||
return false;
|
||||
|
||||
bool smart = true;
|
||||
if (!dynamic_cast<SmartGameObjectAI*>(g->AI()))
|
||||
smart = false;
|
||||
|
||||
if (!smart && !silent)
|
||||
LOG_ERROR("sql.sql", "SmartScript: Action target GameObject(entry: {}) is not using SmartGameObjectAI, action skipped to prevent crash.", g ? g->GetEntry() : (go ? go->GetEntry() : 0));
|
||||
|
||||
return smart;
|
||||
}
|
||||
|
||||
bool SmartScript::IsSmart(bool silent) const
|
||||
{
|
||||
if (me)
|
||||
return IsSmart(me, silent);
|
||||
if (go)
|
||||
return IsSmart(go, silent);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SmartScript::OnReset()
|
||||
@@ -1272,22 +1311,29 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
Milliseconds despawnDelay(e.action.forceDespawn.delay);
|
||||
if (e.action.forceDespawn.removeObjectFromWorld)
|
||||
{
|
||||
if (e.action.forceDespawn.delay || e.action.forceDespawn.forceRespawnTimer)
|
||||
LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_FORCE_DESPAWN has removeObjectFromWorld set. delay and forceRespawnTimer ignored.");
|
||||
|
||||
// Wait at least one world update tick before despawn, so it doesn't break linked actions.
|
||||
if (despawnDelay <= 0ms)
|
||||
{
|
||||
despawnDelay = 1ms;
|
||||
if (Creature* creature = target->ToCreature())
|
||||
creature->AddObjectToRemoveList();
|
||||
else if (GameObject* go = target->ToGameObject())
|
||||
go->AddObjectToRemoveList();
|
||||
}
|
||||
else
|
||||
{
|
||||
Milliseconds despawnDelay(e.action.forceDespawn.delay);
|
||||
|
||||
Seconds forceRespawnTimer(e.action.forceDespawn.forceRespawnTimer);
|
||||
if (Creature* creature = target->ToCreature())
|
||||
{
|
||||
creature->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
|
||||
}
|
||||
else if (GameObject* go = target->ToGameObject())
|
||||
{
|
||||
go->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
|
||||
// Wait at least one world update tick before despawn, so it doesn't break linked actions.
|
||||
if (despawnDelay <= 0ms)
|
||||
despawnDelay = 1ms;
|
||||
|
||||
Seconds forceRespawnTimer(e.action.forceDespawn.forceRespawnTimer);
|
||||
if (Creature* creature = target->ToCreature())
|
||||
creature->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
|
||||
else if (GameObject* go = target->ToGameObject())
|
||||
go->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,10 +1394,22 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
if (IsCreature(target))
|
||||
target->ToCreature()->AI()->SetData(e.action.setData.field, e.action.setData.data);
|
||||
else if (IsGameObject(target))
|
||||
target->ToGameObject()->AI()->SetData(e.action.setData.field, e.action.setData.data);
|
||||
if (Creature* cTarget = target->ToCreature())
|
||||
{
|
||||
CreatureAI* ai = cTarget->AI();
|
||||
if (IsSmart(cTarget))
|
||||
ENSURE_AI(SmartAI, ai)->SetData(e.action.setData.field, e.action.setData.data, me);
|
||||
else
|
||||
ai->SetData(e.action.setData.field, e.action.setData.data);
|
||||
}
|
||||
else if (GameObject* oTarget = target->ToGameObject())
|
||||
{
|
||||
GameObjectAI* ai = oTarget->AI();
|
||||
if (IsSmart(oTarget))
|
||||
ENSURE_AI(SmartGameObjectAI, ai)->SetData(e.action.setData.field, e.action.setData.data, me);
|
||||
else
|
||||
ai->SetData(e.action.setData.field, e.action.setData.data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1737,60 +1795,61 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
|
||||
WorldObject* target = nullptr;
|
||||
|
||||
if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT)
|
||||
switch (e.GetTargetType())
|
||||
{
|
||||
case SMART_TARGET_POSITION:
|
||||
{
|
||||
G3D::Vector3 dest(e.target.x, e.target.y, e.target.z);
|
||||
if (e.action.moveToPos.transport)
|
||||
if (TransportBase* trans = me->GetDirectTransport())
|
||||
trans->CalculatePassengerPosition(dest.x, dest.y, dest.z);
|
||||
|
||||
me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, dest.x, dest.y, dest.z, true, true,
|
||||
isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE, e.target.o);
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_TARGET_RANDOM_POINT:
|
||||
if (me)
|
||||
{
|
||||
float range = (float)e.target.randomPoint.range;
|
||||
Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o };
|
||||
Position randomPoint = me->GetRandomPoint(srcPos, range);
|
||||
me->GetMotionMaster()->MovePoint(
|
||||
e.action.moveToPos.pointId,
|
||||
randomPoint.m_positionX,
|
||||
randomPoint.m_positionY,
|
||||
randomPoint.m_positionZ,
|
||||
true,
|
||||
true,
|
||||
isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE
|
||||
e.action.moveToPos.pointId,
|
||||
randomPoint.m_positionX,
|
||||
randomPoint.m_positionY,
|
||||
randomPoint.m_positionZ,
|
||||
true,
|
||||
true,
|
||||
isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*if (e.GetTargetType() == SMART_TARGET_CREATURE_RANGE || e.GetTargetType() == SMART_TARGET_CREATURE_GUID ||
|
||||
e.GetTargetType() == SMART_TARGET_CREATURE_DISTANCE || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_RANGE ||
|
||||
e.GetTargetType() == SMART_TARGET_GAMEOBJECT_GUID || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_DISTANCE ||
|
||||
e.GetTargetType() == SMART_TARGET_CLOSEST_CREATURE || e.GetTargetType() == SMART_TARGET_CLOSEST_GAMEOBJECT ||
|
||||
e.GetTargetType() == SMART_TARGET_OWNER_OR_SUMMONER || e.GetTargetType() == SMART_TARGET_ACTION_INVOKER ||
|
||||
e.GetTargetType() == SMART_TARGET_CLOSEST_ENEMY || e.GetTargetType() == SMART_TARGET_CLOSEST_FRIENDLY ||
|
||||
e.GetTargetType() == SMART_TARGET_SELF || e.GetTargetType() == SMART_TARGET_STORED)) */
|
||||
{
|
||||
// we want to move to random element
|
||||
if (!targets.empty())
|
||||
target = Acore::Containers::SelectRandomContainerElement(targets);
|
||||
}
|
||||
|
||||
if (!target)
|
||||
{
|
||||
G3D::Vector3 dest(e.target.x, e.target.y, e.target.z);
|
||||
if (e.action.moveToPos.transport)
|
||||
if (TransportBase* trans = me->GetDirectTransport())
|
||||
trans->CalculatePassengerPosition(dest.x, dest.y, dest.z);
|
||||
|
||||
me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, dest.x, dest.y, dest.z, true, true,
|
||||
isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE, e.target.o);
|
||||
}
|
||||
else // Xinef: we can use dest.x, dest.y, dest.z to make offset
|
||||
{
|
||||
float x, y, z;
|
||||
target->GetPosition(x, y, z);
|
||||
if (e.action.moveToPos.ContactDistance > 0)
|
||||
// Can use target floats as offset
|
||||
default:
|
||||
{
|
||||
target->GetNearPoint(me, x, y, z, e.action.moveToPos.ContactDistance, 0, target->GetAngle(me));
|
||||
// we want to move to random element
|
||||
if (targets.empty())
|
||||
return;
|
||||
else
|
||||
target = Acore::Containers::SelectRandomContainerElement(targets);
|
||||
|
||||
float x, y, z;
|
||||
target->GetPosition(x, y, z);
|
||||
|
||||
if (e.action.moveToPos.combatReach)
|
||||
target->GetNearPoint(me, x, y, z, target->GetCombatReach() + e.action.moveToPos.ContactDistance, 0, target->GetAngle(me));
|
||||
else if (e.action.moveToPos.ContactDistance)
|
||||
target->GetNearPoint(me, x, y, z, e.action.moveToPos.ContactDistance, 0, target->GetAngle(me));
|
||||
|
||||
me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, x + e.target.x, y + e.target.y, z + e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE);
|
||||
|
||||
break;
|
||||
}
|
||||
me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, x + e.target.x, y + e.target.y, z + e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_MOVE_TO_POS_TARGET:
|
||||
@@ -1966,7 +2025,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
else if (GameObject* go = target->ToGameObject())
|
||||
{
|
||||
if (IsSmartGO(go))
|
||||
if (IsSmart(go))
|
||||
CAST_AI(SmartGameObjectAI, go->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker());
|
||||
}
|
||||
}
|
||||
@@ -2053,7 +2112,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
else if (GameObject* go = target->ToGameObject())
|
||||
{
|
||||
if (IsSmartGO(go))
|
||||
if (IsSmart(go))
|
||||
CAST_AI(SmartGameObjectAI, go->AI())->SetScript9(e, id, GetLastInvoker());
|
||||
}
|
||||
}
|
||||
@@ -2077,7 +2136,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
else if (GameObject* go = target->ToGameObject())
|
||||
{
|
||||
if (IsSmartGO(go))
|
||||
if (IsSmart(go))
|
||||
CAST_AI(SmartGameObjectAI, go->AI())->SetScript9(e, id, GetLastInvoker());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ public:
|
||||
void DoFindFriendlyMissingBuff(std::vector<Creature*>& creatures, float range, uint32 spellid) const;
|
||||
Unit* DoFindClosestFriendlyInRange(float range, bool playerOnly) const;
|
||||
|
||||
bool IsSmart(Creature* c, bool silent = false) const;
|
||||
bool IsSmart(GameObject* g, bool silent = false) const;
|
||||
bool IsSmart(bool silent = false) const;
|
||||
|
||||
void StoreTargetList(ObjectVector const& targets, uint32 id)
|
||||
{
|
||||
// insert or replace
|
||||
@@ -83,35 +87,6 @@ public:
|
||||
_storedTargets.emplace(id, ObjectGuidVector(targets));
|
||||
}
|
||||
|
||||
bool IsSmart(Creature* c = nullptr)
|
||||
{
|
||||
bool smart = true;
|
||||
if (c && c->GetAIName() != "SmartAI")
|
||||
smart = false;
|
||||
|
||||
if (!me || me->GetAIName() != "SmartAI")
|
||||
smart = false;
|
||||
|
||||
if (!smart)
|
||||
LOG_ERROR("sql.sql", "SmartScript: Action target Creature(entry: {}) is not using SmartAI, action skipped to prevent crash.", c ? c->GetEntry() : (me ? me->GetEntry() : 0));
|
||||
|
||||
return smart;
|
||||
}
|
||||
|
||||
bool IsSmartGO(GameObject* g = nullptr)
|
||||
{
|
||||
bool smart = true;
|
||||
if (g && g->GetAIName() != "SmartGameObjectAI")
|
||||
smart = false;
|
||||
|
||||
if (!go || go->GetAIName() != "SmartGameObjectAI")
|
||||
smart = false;
|
||||
if (!smart)
|
||||
LOG_ERROR("sql.sql", "SmartScript: Action target GameObject(entry: {}) is not using SmartGameObjectAI, action skipped to prevent crash.", g ? g->GetEntry() : (go ? go->GetEntry() : 0));
|
||||
|
||||
return smart;
|
||||
}
|
||||
|
||||
ObjectVector const* GetStoredTargetVector(uint32 id, WorldObject const& ref) const
|
||||
{
|
||||
auto itr = _storedTargets.find(id);
|
||||
|
||||
@@ -346,6 +346,7 @@ void SmartAIMgr::LoadSmartAIFromDB()
|
||||
case SMART_EVENT_TRANSPORT_ADDCREATURE:
|
||||
case SMART_EVENT_NEAR_PLAYERS:
|
||||
case SMART_EVENT_SUMMONED_UNIT_EVADE:
|
||||
case SMART_EVENT_DATA_SET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -978,6 +978,7 @@ struct SmartAction
|
||||
{
|
||||
uint32 delay;
|
||||
uint32 forceRespawnTimer;
|
||||
SAIBool removeObjectFromWorld;
|
||||
} forceDespawn;
|
||||
|
||||
struct
|
||||
@@ -1201,6 +1202,7 @@ struct SmartAction
|
||||
SAIBool transport;
|
||||
uint32 controlled;
|
||||
uint32 ContactDistance;
|
||||
uint32 combatReach;
|
||||
} moveToPos;
|
||||
|
||||
struct
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
Player* ChatHandler::GetPlayer() const
|
||||
{
|
||||
@@ -888,3 +889,105 @@ int CliHandler::GetSessionDbLocaleIndex() const
|
||||
{
|
||||
return sObjectMgr->GetDBCLocaleIndex();
|
||||
}
|
||||
|
||||
bool AddonChannelCommandHandler::ParseCommands(std::string_view str)
|
||||
{
|
||||
if (memcmp(str.data(), "AzerothCore\t", 12))
|
||||
return false;
|
||||
char opcode = str[12];
|
||||
if (!opcode) // str[12] is opcode
|
||||
return false;
|
||||
if (!str[13] || !str[14] || !str[15] || !str[16]) // str[13] through str[16] is 4-character command counter
|
||||
return false;
|
||||
echo = str.substr(13);
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case 'p': // p Ping
|
||||
SendAck();
|
||||
return true;
|
||||
case 'h': // h Issue human-readable command
|
||||
case 'i': // i Issue command
|
||||
if (!str[17])
|
||||
return false;
|
||||
humanReadable = (opcode == 'h');
|
||||
if (_ParseCommands(str.substr(17))) // actual command starts at str[17]
|
||||
{
|
||||
if (!hadAck)
|
||||
SendAck();
|
||||
if (HasSentErrorMessage())
|
||||
SendFailed();
|
||||
else
|
||||
SendOK();
|
||||
}
|
||||
else
|
||||
{
|
||||
SendSysMessage(LANG_CMD_INVALID);
|
||||
SendFailed();
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AddonChannelCommandHandler::Send(std::string const& msg)
|
||||
{
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, LANG_ADDON, GetSession()->GetPlayer(), GetSession()->GetPlayer(), msg);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void AddonChannelCommandHandler::SendAck() // a Command acknowledged, no body
|
||||
{
|
||||
ASSERT(echo.size());
|
||||
std::string ack = "AzerothCore\ta";
|
||||
ack.resize(18);
|
||||
memcpy(&ack[13], echo.data(), 4);
|
||||
ack[17] = '\0';
|
||||
Send(ack);
|
||||
hadAck = true;
|
||||
}
|
||||
|
||||
void AddonChannelCommandHandler::SendOK() // o Command OK, no body
|
||||
{
|
||||
ASSERT(echo.size());
|
||||
std::string ok = "AzerothCore\to";
|
||||
ok.resize(18);
|
||||
memcpy(&ok[13], echo.data(), 4);
|
||||
ok[17] = '\0';
|
||||
Send(ok);
|
||||
}
|
||||
|
||||
void AddonChannelCommandHandler::SendFailed() // f Command failed, no body
|
||||
{
|
||||
ASSERT(echo.size());
|
||||
std::string fail = "AzerothCore\tf";
|
||||
fail.resize(18);
|
||||
memcpy(&fail[13], echo.data(), 4);
|
||||
fail[17] = '\0';
|
||||
Send(fail);
|
||||
}
|
||||
|
||||
// m Command message, message in body
|
||||
void AddonChannelCommandHandler::SendSysMessage(std::string_view str, bool escapeCharacters)
|
||||
{
|
||||
ASSERT(echo.size());
|
||||
if (!hadAck)
|
||||
SendAck();
|
||||
|
||||
std::string msg = "AzerothCore\tm";
|
||||
msg.append(echo.data(), 4);
|
||||
std::string body(str);
|
||||
if (escapeCharacters)
|
||||
boost::replace_all(body, "|", "||");
|
||||
size_t pos, lastpos;
|
||||
for (lastpos = 0, pos = body.find('\n', lastpos); pos != std::string::npos; lastpos = pos + 1, pos = body.find('\n', lastpos))
|
||||
{
|
||||
std::string line(msg);
|
||||
line.append(body, lastpos, pos - lastpos);
|
||||
Send(line);
|
||||
}
|
||||
msg.append(body, lastpos, pos - lastpos);
|
||||
Send(msg);
|
||||
}
|
||||
|
||||
@@ -168,4 +168,24 @@ private:
|
||||
Print* m_print;
|
||||
};
|
||||
|
||||
class AC_GAME_API AddonChannelCommandHandler : public ChatHandler
|
||||
{
|
||||
public:
|
||||
using ChatHandler::ChatHandler;
|
||||
bool ParseCommands(std::string_view str) override;
|
||||
void SendSysMessage(std::string_view str, bool escapeCharacters) override;
|
||||
using ChatHandler::SendSysMessage;
|
||||
bool IsHumanReadable() const override { return humanReadable; }
|
||||
|
||||
private:
|
||||
void Send(std::string const& msg);
|
||||
void SendAck();
|
||||
void SendOK();
|
||||
void SendFailed();
|
||||
|
||||
std::string echo;
|
||||
bool hadAck = false;
|
||||
bool humanReadable = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1054,10 +1054,10 @@ void ConditionMgr::LoadConditions(bool isReload)
|
||||
LootTemplates_Spell.ResetConditions();
|
||||
LootTemplates_Player.ResetConditions();
|
||||
|
||||
LOG_INFO("server.loading", "Re-Loading `gossip_menu` Table for Conditions!");
|
||||
LOG_INFO("server.loading", "Reloading `gossip_menu` Table for Conditions!");
|
||||
sObjectMgr->LoadGossipMenu();
|
||||
|
||||
LOG_INFO("server.loading", "Re-Loading `gossip_menu_option` Table for Conditions!");
|
||||
LOG_INFO("server.loading", "Reloading `gossip_menu_option` Table for Conditions!");
|
||||
sObjectMgr->LoadGossipMenuItems();
|
||||
sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists();
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore(SpellFocusObjectfmt);
|
||||
DBCStorage <SpellRadiusEntry> sSpellRadiusStore(SpellRadiusfmt);
|
||||
DBCStorage <SpellRangeEntry> sSpellRangeStore(SpellRangefmt);
|
||||
DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore(SpellRuneCostfmt);
|
||||
DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftfmt);
|
||||
DBCStorage <SpellShapeshiftFormEntry> sSpellShapeshiftFormStore(SpellShapeshiftFormEntryfmt);
|
||||
DBCStorage <SpellVisualEntry> sSpellVisualStore(SpellVisualfmt);
|
||||
DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
|
||||
DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt);
|
||||
@@ -375,7 +375,7 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
LOAD_DBC(sSpellRadiusStore, "SpellRadius.dbc", "spellradius_dbc");
|
||||
LOAD_DBC(sSpellRangeStore, "SpellRange.dbc", "spellrange_dbc");
|
||||
LOAD_DBC(sSpellRuneCostStore, "SpellRuneCost.dbc", "spellrunecost_dbc");
|
||||
LOAD_DBC(sSpellShapeshiftStore, "SpellShapeshiftForm.dbc", "spellshapeshiftform_dbc");
|
||||
LOAD_DBC(sSpellShapeshiftFormStore, "SpellShapeshiftForm.dbc", "spellshapeshiftform_dbc");
|
||||
LOAD_DBC(sSpellVisualStore, "SpellVisual.dbc", "spellvisual_dbc");
|
||||
LOAD_DBC(sStableSlotPricesStore, "StableSlotPrices.dbc", "stableslotprices_dbc");
|
||||
LOAD_DBC(sSummonPropertiesStore, "SummonProperties.dbc", "summonproperties_dbc");
|
||||
|
||||
@@ -139,7 +139,7 @@ extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore;
|
||||
extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore;
|
||||
extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore;
|
||||
extern DBCStorage <ItemSetEntry> sItemSetStore;
|
||||
extern DBCStorage <LFGDungeonEntry> sLFGDungeonStore;
|
||||
extern DBCStorage <LFGDungeonEntry> sLFGDungeonStore;
|
||||
extern DBCStorage <LiquidTypeEntry> sLiquidTypeStore;
|
||||
extern DBCStorage <LockEntry> sLockStore;
|
||||
extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
|
||||
@@ -175,7 +175,7 @@ extern std::unordered_set<uint32> sPetTalentSpells;
|
||||
extern DBCStorage <SpellRadiusEntry> sSpellRadiusStore;
|
||||
extern DBCStorage <SpellRangeEntry> sSpellRangeStore;
|
||||
extern DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore;
|
||||
extern DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore;
|
||||
extern DBCStorage <SpellShapeshiftFormEntry> sSpellShapeshiftFormStore;
|
||||
extern DBCStorage <SpellEntry> sSpellStore;
|
||||
extern DBCStorage <SpellVisualEntry> sSpellVisualStore;
|
||||
extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore;
|
||||
|
||||
@@ -2173,15 +2173,6 @@ bool GameObject::IsInRange(float x, float y, float z, float radius) const
|
||||
&& dz < (info->maxZ * scale) + radius && dz > (info->minZ * scale) - radius;
|
||||
}
|
||||
|
||||
void GameObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin, Player const* skipped_rcvr) const
|
||||
{
|
||||
dist += GetObjectSize();
|
||||
if (includeMargin)
|
||||
dist += VISIBILITY_COMPENSATION * 2.0f; // pussywizard: to ensure everyone receives all important packets
|
||||
Acore::MessageDistDeliverer notifier(this, data, dist, false, skipped_rcvr);
|
||||
Cell::VisitWorldObjects(this, notifier, dist);
|
||||
}
|
||||
|
||||
void GameObject::EventInform(uint32 eventId)
|
||||
{
|
||||
if (!eventId)
|
||||
|
||||
@@ -289,8 +289,6 @@ public:
|
||||
void SendCustomAnim(uint32 anim);
|
||||
[[nodiscard]] bool IsInRange(float x, float y, float z, float radius) const;
|
||||
|
||||
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin = false, Player const* skipped_rcvr = nullptr) const override; // pussywizard!
|
||||
|
||||
void ModifyHealth(int32 change, Unit* attackerOrHealer = nullptr, uint32 spellId = 0);
|
||||
void SetDestructibleBuildingModifyState(bool allow) { m_allowModifyDestructibleBuilding = allow; }
|
||||
// sets GameObject type 33 destruction flags and optionally default health for that state
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Define.h"
|
||||
#include "Item.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
@@ -2077,15 +2077,24 @@ void Unit::BuildHeartBeatMsg(WorldPacket* data) const
|
||||
BuildMovementPacket(data);
|
||||
}
|
||||
|
||||
void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin, Player const* skipped_rcvr) const
|
||||
void WorldObject::SendMessageToSet(WorldPacket const* data, bool self) const
|
||||
{
|
||||
dist += GetObjectSize();
|
||||
if (includeMargin)
|
||||
dist += VISIBILITY_COMPENSATION; // pussywizard: to ensure everyone receives all important packets
|
||||
Acore::MessageDistDeliverer notifier(this, data, dist, false, skipped_rcvr);
|
||||
if (IsInWorld())
|
||||
SendMessageToSetInRange(data, GetVisibilityRange(), self);
|
||||
}
|
||||
|
||||
void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/) const
|
||||
{
|
||||
Acore::MessageDistDeliverer notifier(this, data, dist);
|
||||
Cell::VisitWorldObjects(this, notifier, dist);
|
||||
}
|
||||
|
||||
void WorldObject::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const
|
||||
{
|
||||
Acore::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr);
|
||||
Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
|
||||
}
|
||||
|
||||
void WorldObject::SendObjectDeSpawnAnim(ObjectGuid guid)
|
||||
{
|
||||
WorldPacket data(SMSG_GAMEOBJECT_DESPAWN_ANIM, 8);
|
||||
|
||||
@@ -479,9 +479,9 @@ public:
|
||||
|
||||
virtual void CleanupsBeforeDelete(bool finalCleanup = true); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units
|
||||
|
||||
virtual void SendMessageToSet(WorldPacket const* data, bool self) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), self, true); } // pussywizard!
|
||||
virtual void SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin = false, Player const* skipped_rcvr = nullptr) const; // pussywizard!
|
||||
virtual void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), false, true, skipped_rcvr); } // pussywizard!
|
||||
virtual void SendMessageToSet(WorldPacket const* data, bool self) const;
|
||||
virtual void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self) const;
|
||||
virtual void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const;
|
||||
|
||||
virtual uint8 getLevelForTarget(WorldObject const* /*target*/) const { return 1; }
|
||||
|
||||
|
||||
@@ -394,7 +394,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
|
||||
// Send fake summon spell cast - this is needed for correct cooldown application for spells
|
||||
// Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside
|
||||
/// @todo pets should be summoned from real cast instead of just faking it?
|
||||
if (petInfo->CreatedBySpellId)
|
||||
if (petInfo->CreatedBySpellId && spellInfo && (spellInfo->CategoryRecoveryTime > 0 || spellInfo->RecoveryTime > 0))
|
||||
{
|
||||
WorldPacket data(SMSG_SPELL_GO, (8 + 8 + 4 + 4 + 2));
|
||||
data << owner->GetPackGUID();
|
||||
@@ -2499,11 +2499,6 @@ float Pet::GetNativeObjectScale() const
|
||||
{
|
||||
uint8 ctFamily = GetCreatureTemplate()->family;
|
||||
|
||||
// hackfix: Edge case where DBC scale values for DEVILSAUR pets make them too small.
|
||||
// Therefore we take data from spirit beast instead.
|
||||
if (ctFamily && ctFamily == CREATURE_FAMILY_DEVILSAUR)
|
||||
ctFamily = CREATURE_FAMILY_SPIRIT_BEAST;
|
||||
|
||||
CreatureFamilyEntry const* creatureFamily = sCreatureFamilyStore.LookupEntry(ctFamily);
|
||||
if (creatureFamily && creatureFamily->minScale > 0.0f && getPetType() & HUNTER_PET)
|
||||
{
|
||||
@@ -2520,6 +2515,13 @@ float Pet::GetNativeObjectScale() const
|
||||
|
||||
float scale = (creatureFamily->maxScale - creatureFamily->minScale) * scaleMod + creatureFamily->minScale;
|
||||
|
||||
scale = std::min(scale, creatureFamily->maxScale);
|
||||
|
||||
if (CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId()))
|
||||
{
|
||||
if (scale < 1.f && displayInfo->scale > 1.f)
|
||||
scale *= displayInfo->scale;
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
|
||||
@@ -5612,25 +5612,40 @@ void Player::SaveRecallPosition()
|
||||
m_recallO = GetOrientation();
|
||||
}
|
||||
|
||||
void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin, Player const* skipped_rcvr) const
|
||||
void Player::SendMessageToSet(WorldPacket const* data, bool self) const
|
||||
{
|
||||
SendMessageToSetInRange(data, GetVisibilityRange(), self);
|
||||
}
|
||||
|
||||
void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self) const
|
||||
{
|
||||
if (self)
|
||||
GetSession()->SendPacket(data);
|
||||
SendDirectMessage(data);
|
||||
|
||||
Acore::MessageDistDeliverer notifier(this, data, dist);
|
||||
Cell::VisitWorldObjects(this, notifier, dist);
|
||||
}
|
||||
|
||||
void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin, bool ownTeamOnly, bool required3dDist) const
|
||||
{
|
||||
if (self)
|
||||
SendDirectMessage(data);
|
||||
|
||||
dist += GetObjectSize();
|
||||
if (includeMargin)
|
||||
dist += VISIBILITY_COMPENSATION; // pussywizard: to ensure everyone receives all important packets
|
||||
Acore::MessageDistDeliverer notifier(this, data, dist, false, skipped_rcvr);
|
||||
|
||||
Acore::MessageDistDeliverer notifier(this, data, dist, ownTeamOnly, nullptr, required3dDist);
|
||||
Cell::VisitWorldObjects(this, notifier, dist);
|
||||
}
|
||||
|
||||
void Player::SendMessageToSetInRange_OwnTeam(WorldPacket const* data, float dist, bool self) const
|
||||
void Player::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const
|
||||
{
|
||||
if (self)
|
||||
GetSession()->SendPacket(data);
|
||||
if (skipped_rcvr != this)
|
||||
SendDirectMessage(data);
|
||||
|
||||
Acore::MessageDistDeliverer notifier(this, data, dist, true);
|
||||
Cell::VisitWorldObjects(this, notifier, dist);
|
||||
Acore::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr);
|
||||
Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
|
||||
}
|
||||
|
||||
void Player::SendDirectMessage(WorldPacket const* data) const
|
||||
@@ -9291,7 +9306,7 @@ void Player::Say(std::string_view text, Language language, WorldObject const* /*
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, language, this, this, _text);
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true);
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true, false, false, true);
|
||||
}
|
||||
|
||||
void Player::Say(uint32 textId, WorldObject const* target /*= nullptr*/)
|
||||
@@ -9312,7 +9327,7 @@ void Player::Yell(std::string_view text, Language language, WorldObject const* /
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, language, this, this, _text);
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), true);
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), true, false, false, true);
|
||||
}
|
||||
|
||||
void Player::Yell(uint32 textId, WorldObject const* target /*= nullptr*/)
|
||||
@@ -9334,14 +9349,7 @@ void Player::TextEmote(std::string_view text, WorldObject const* /*= nullptr*/,
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text);
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_EMOTE))
|
||||
{
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessageToSetInRange_OwnTeam(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true);
|
||||
}
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, false, !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_EMOTE), true);
|
||||
}
|
||||
|
||||
void Player::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool /*isBossEmote = false*/)
|
||||
@@ -10521,7 +10529,7 @@ void Player::InitDataForForm(bool reapplyMods)
|
||||
{
|
||||
ShapeshiftForm form = GetShapeshiftForm();
|
||||
|
||||
SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(form);
|
||||
SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
|
||||
if (ssEntry && ssEntry->attackSpeed)
|
||||
{
|
||||
SetAttackTime(BASE_ATTACK, ssEntry->attackSpeed);
|
||||
|
||||
@@ -2000,11 +2000,10 @@ public:
|
||||
|
||||
void ProcessTerrainStatusUpdate() override;
|
||||
|
||||
void SendMessageToSet(WorldPacket const* data, bool self) const override { SendMessageToSetInRange(data, GetVisibilityRange(), self, true); } // pussywizard!
|
||||
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin = false, Player const* skipped_rcvr = nullptr) const override; // pussywizard!
|
||||
void SendMessageToSetInRange_OwnTeam(WorldPacket const* data, float dist, bool self) const; // pussywizard! param includeMargin not needed here
|
||||
void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const override { SendMessageToSetInRange(data, GetVisibilityRange(), skipped_rcvr != this, true, skipped_rcvr); } // pussywizard!
|
||||
|
||||
void SendMessageToSet(WorldPacket const* data, bool self) const override;
|
||||
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self) const override;
|
||||
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin, bool ownTeamOnly, bool required3dDist = false) const;
|
||||
void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const override;
|
||||
void SendTeleportAckPacket();
|
||||
|
||||
[[nodiscard]] Corpse* GetCorpse() const;
|
||||
|
||||
@@ -753,7 +753,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
else
|
||||
{
|
||||
sScriptMgr->OnGivePlayerXP(this, XP, nullptr, isLFGReward ? PlayerXPSource::XPSOURCE_QUEST_DF : PlayerXPSource::XPSOURCE_QUEST);
|
||||
GiveXP(XP, nullptr, isLFGReward);
|
||||
GiveXP(XP, nullptr, 1.0f, isLFGReward);
|
||||
}
|
||||
|
||||
// Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative
|
||||
|
||||
@@ -3453,7 +3453,8 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool Ca
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
// Return evade for units in evade mode
|
||||
if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks() && !spell->HasAura(SPELL_AURA_CONTROL_VEHICLE) && !spell->HasAttribute(SPELL_ATTR0_CU_IGNORE_EVADE))
|
||||
if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks() && !spell->HasAura(SPELL_AURA_CONTROL_VEHICLE)
|
||||
&& !spell->HasAttribute(SPELL_ATTR0_CU_IGNORE_EVADE) && !spell->HasAttribute(SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT))
|
||||
return SPELL_MISS_EVADE;
|
||||
|
||||
// Try victim reflect spell
|
||||
@@ -3528,7 +3529,7 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, Spell const* spell, bool CanRef
|
||||
|
||||
// Return evade for units in evade mode
|
||||
if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks() && !spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE) &&
|
||||
!spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_EVADE))
|
||||
!spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_EVADE) && !spellInfo->HasAttribute(SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT))
|
||||
{
|
||||
return SPELL_MISS_EVADE;
|
||||
}
|
||||
@@ -5384,7 +5385,8 @@ void Unit::RemoveEvadeAuras()
|
||||
{
|
||||
Aura const* aura = iter->second->GetBase();
|
||||
SpellInfo const* spellInfo = aura->GetSpellInfo();
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_EVADE) || spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE) || spellInfo->HasAura(SPELL_AURA_CLONE_CASTER) || (aura->IsPassive() && GetOwnerGUID().IsPlayer()))
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_EVADE) || spellInfo->HasAttribute(SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT) || spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)
|
||||
|| spellInfo->HasAura(SPELL_AURA_CLONE_CASTER) || (aura->IsPassive() && GetOwnerGUID().IsPlayer()))
|
||||
++iter;
|
||||
else
|
||||
_UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT);
|
||||
@@ -5394,7 +5396,8 @@ void Unit::RemoveEvadeAuras()
|
||||
{
|
||||
Aura* aura = iter->second;
|
||||
SpellInfo const* spellInfo = aura->GetSpellInfo();
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_EVADE) || spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE) || spellInfo->HasAura(SPELL_AURA_CLONE_CASTER) || (aura->IsPassive() && GetOwnerGUID().IsPlayer()))
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_EVADE) || spellInfo->HasAttribute(SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT) || spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)
|
||||
|| spellInfo->HasAura(SPELL_AURA_CLONE_CASTER) || (aura->IsPassive() && GetOwnerGUID().IsPlayer()))
|
||||
++iter;
|
||||
else
|
||||
RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT);
|
||||
@@ -15190,7 +15193,7 @@ uint32 Unit::GetCreatureType() const
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
ShapeshiftForm form = GetShapeshiftForm();
|
||||
SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(form);
|
||||
SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
|
||||
if (ssEntry && ssEntry->creatureType > 0)
|
||||
return ssEntry->creatureType;
|
||||
else
|
||||
@@ -19677,7 +19680,7 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form, uint32 spellId) const
|
||||
}
|
||||
|
||||
uint32 modelid = 0;
|
||||
SpellShapeshiftEntry const* formEntry = sSpellShapeshiftStore.LookupEntry(form);
|
||||
SpellShapeshiftFormEntry const* formEntry = sSpellShapeshiftFormStore.LookupEntry(form);
|
||||
if (formEntry && formEntry->modelID_A)
|
||||
{
|
||||
// Take the alliance modelid as default
|
||||
@@ -21613,7 +21616,7 @@ bool Unit::IsInDisallowedMountForm() const
|
||||
|
||||
if (ShapeshiftForm form = GetShapeshiftForm())
|
||||
{
|
||||
SpellShapeshiftEntry const* shapeshift = sSpellShapeshiftStore.LookupEntry(form);
|
||||
SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.LookupEntry(form);
|
||||
if (!shapeshift)
|
||||
{
|
||||
return true;
|
||||
@@ -21656,6 +21659,20 @@ bool Unit::IsInDisallowedMountForm() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void Unit::SetUInt32Value(uint16 index, uint32 value)
|
||||
{
|
||||
Object::SetUInt32Value(index, value);
|
||||
|
||||
switch (index)
|
||||
{
|
||||
// Invalidating the cache on health change should fix an issue where the client sees dead NPCs when they are not.
|
||||
// We might also need to invalidate the cache for some other fields as well.
|
||||
case UNIT_FIELD_HEALTH:
|
||||
InvalidateValuesUpdateCache();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Unit::GetDebugInfo() const
|
||||
{
|
||||
std::stringstream sstr;
|
||||
|
||||
@@ -1571,6 +1571,8 @@ public:
|
||||
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply);
|
||||
void ApplyCastTimePercentMod(float val, bool apply);
|
||||
|
||||
void SetUInt32Value(uint16 index, uint32 value);
|
||||
|
||||
UnitFlags GetUnitFlags() const { return UnitFlags(GetUInt32Value(UNIT_FIELD_FLAGS)); }
|
||||
bool HasUnitFlag(UnitFlags flags) const { return HasFlag(UNIT_FIELD_FLAGS, flags); }
|
||||
void SetUnitFlag(UnitFlags flags) { SetFlag(UNIT_FIELD_FLAGS, flags); }
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Unit.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include "Unit.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Acore::Impl::EnumUtilsImpl
|
||||
|
||||
@@ -217,8 +217,14 @@ void MessageDistDeliverer::Visit(PlayerMapType& m)
|
||||
if (!target->InSamePhase(i_phaseMask))
|
||||
continue;
|
||||
|
||||
if (target->GetExactDist2dSq(i_source) > i_distSq)
|
||||
continue;
|
||||
if (required3dDist)
|
||||
{
|
||||
if (target->GetExactDistSq(i_source) > i_distSq)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if (target->GetExactDist2dSq(i_source) > i_distSq)
|
||||
continue;
|
||||
|
||||
// Send packet to all who are sharing the player's vision
|
||||
if (target->HasSharedVision())
|
||||
@@ -242,8 +248,14 @@ void MessageDistDeliverer::Visit(CreatureMapType& m)
|
||||
if (!target->HasSharedVision() || !target->InSamePhase(i_phaseMask))
|
||||
continue;
|
||||
|
||||
if (target->GetExactDist2dSq(i_source) > i_distSq)
|
||||
continue;
|
||||
if (required3dDist)
|
||||
{
|
||||
if (target->GetExactDistSq(i_source) > i_distSq)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if (target->GetExactDist2dSq(i_source) > i_distSq)
|
||||
continue;
|
||||
|
||||
// Send packet to all who are sharing the creature's vision
|
||||
SharedVisionList::const_iterator i = target->GetSharedVisionList().begin();
|
||||
@@ -265,8 +277,14 @@ void MessageDistDeliverer::Visit(DynamicObjectMapType& m)
|
||||
if (!target->IsViewpoint())
|
||||
continue;
|
||||
|
||||
if (target->GetExactDist2dSq(i_source) > i_distSq)
|
||||
continue;
|
||||
if (required3dDist)
|
||||
{
|
||||
if (target->GetExactDistSq(i_source) > i_distSq)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if (target->GetExactDist2dSq(i_source) > i_distSq)
|
||||
continue;
|
||||
|
||||
// Send packet back to the caster if the caster has vision of dynamic object
|
||||
Player* caster = (Player*)target->GetCaster();
|
||||
|
||||
@@ -102,10 +102,11 @@ namespace Acore
|
||||
float i_distSq;
|
||||
TeamId teamId;
|
||||
Player const* skipped_receiver;
|
||||
MessageDistDeliverer(WorldObject const* src, WorldPacket const* msg, float dist, bool own_team_only = false, Player const* skipped = nullptr)
|
||||
bool required3dDist;
|
||||
MessageDistDeliverer(WorldObject const* src, WorldPacket const* msg, float dist, bool own_team_only = false, Player const* skipped = nullptr, bool req3dDist = false)
|
||||
: i_source(src), i_message(msg), i_phaseMask(src->GetPhaseMask()), i_distSq(dist * dist)
|
||||
, teamId((own_team_only && src->GetTypeId() == TYPEID_PLAYER) ? src->ToPlayer()->GetTeamId() : TEAM_NEUTRAL)
|
||||
, skipped_receiver(skipped)
|
||||
, skipped_receiver(skipped), required3dDist(req3dDist)
|
||||
{
|
||||
}
|
||||
void Visit(PlayerMapType& m);
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
|
||||
Roll::Roll(ObjectGuid _guid, LootItem const& li) : itemGUID(_guid), itemid(li.itemid),
|
||||
itemRandomPropId(li.randomPropertyId), itemRandomSuffix(li.randomSuffix), itemCount(li.count),
|
||||
@@ -896,7 +898,7 @@ void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p,
|
||||
p->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll)
|
||||
void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll, bool autoPass)
|
||||
{
|
||||
WorldPacket data(SMSG_LOOT_ROLL, (8 + 4 + 8 + 4 + 4 + 4 + 1 + 1 + 1));
|
||||
data << sourceGuid; // guid of the item rolled
|
||||
@@ -907,7 +909,7 @@ void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rol
|
||||
data << uint32(roll.itemRandomPropId); // Item random property ID
|
||||
data << uint8(rollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number
|
||||
data << uint8(rollType); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll
|
||||
data << uint8(0); // 1: "You automatically passed on: %s because you cannot loot that item." - Possibly used in need befor greed
|
||||
data << uint8(autoPass); // 1: "You automatically passed on: %s because you cannot loot that item."
|
||||
|
||||
for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr)
|
||||
{
|
||||
@@ -984,6 +986,23 @@ void Group::SendLooter(Creature* creature, Player* groupLooter)
|
||||
BroadcastPacket(&data, false);
|
||||
}
|
||||
|
||||
bool CanRollOnItem(LootItem const& item, Player const* player, Loot* loot)
|
||||
{
|
||||
// Players can't roll on unique items if they already reached the maximum quantity of that item
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid);
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
uint32 itemCount = player->GetItemCount(item.itemid);
|
||||
if ((proto->MaxCount > 0 && static_cast<int32>(itemCount) >= proto->MaxCount) || (player->CanEquipUniqueItem(proto) != EQUIP_ERR_OK))
|
||||
return false;
|
||||
|
||||
if (!item.AllowedForPlayer(player, loot->sourceWorldObjectGUID))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
|
||||
{
|
||||
std::vector<LootItem>::iterator i;
|
||||
@@ -1011,23 +1030,20 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
|
||||
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member)
|
||||
if (!member || !member->GetSession())
|
||||
continue;
|
||||
if (member->IsAtLootRewardDistance(pLootedObject))
|
||||
{
|
||||
if (i->AllowedForPlayer(member, loot->sourceWorldObjectGUID))
|
||||
{
|
||||
r->totalPlayersRolling++;
|
||||
r->totalPlayersRolling++;
|
||||
|
||||
if (member->GetPassOnGroupLoot())
|
||||
{
|
||||
r->playerVote[member->GetGUID()] = PASS;
|
||||
r->totalPass++;
|
||||
// can't broadcast the pass now. need to wait until all rolling players are known.
|
||||
}
|
||||
else
|
||||
r->playerVote[member->GetGUID()] = NOT_EMITED_YET;
|
||||
RollVote vote = member->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET;
|
||||
if (!CanRollOnItem(*i, member, loot))
|
||||
{
|
||||
vote = PASS;
|
||||
++r->totalPass;
|
||||
}
|
||||
|
||||
r->playerVote[member->GetGUID()] = vote;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1050,23 +1066,28 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
|
||||
continue;
|
||||
|
||||
if (itr->second == PASS)
|
||||
SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r);
|
||||
SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r, true);
|
||||
}
|
||||
}
|
||||
|
||||
SendLootStartRoll(60000, pLootedObject->GetMapId(), *r);
|
||||
|
||||
RollId.push_back(r);
|
||||
|
||||
if (Creature* creature = pLootedObject->ToCreature())
|
||||
if (r->totalPass == r->totalPlayersRolling)
|
||||
delete r;
|
||||
else
|
||||
{
|
||||
creature->m_groupLootTimer = 60000;
|
||||
creature->lootingGroupLowGUID = GetGUID().GetCounter();
|
||||
}
|
||||
else if (GameObject* go = pLootedObject->ToGameObject())
|
||||
{
|
||||
go->m_groupLootTimer = 60000;
|
||||
go->lootingGroupLowGUID = GetGUID().GetCounter();
|
||||
SendLootStartRoll(60000, pLootedObject->GetMapId(), *r);
|
||||
|
||||
RollId.push_back(r);
|
||||
|
||||
if (Creature* creature = pLootedObject->ToCreature())
|
||||
{
|
||||
creature->m_groupLootTimer = 60000;
|
||||
creature->lootingGroupLowGUID = GetGUID().GetCounter();
|
||||
}
|
||||
else if (GameObject* go = pLootedObject->ToGameObject())
|
||||
{
|
||||
go->m_groupLootTimer = 60000;
|
||||
go->lootingGroupLowGUID = GetGUID().GetCounter();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1094,16 +1115,18 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
|
||||
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member)
|
||||
if (!member || !member->GetSession())
|
||||
continue;
|
||||
|
||||
if (member->IsAtLootRewardDistance(pLootedObject))
|
||||
{
|
||||
if (i->AllowedForPlayer(member, loot->sourceWorldObjectGUID))
|
||||
RollVote vote = NOT_EMITED_YET;
|
||||
if (!CanRollOnItem(*i, member, loot))
|
||||
{
|
||||
r->totalPlayersRolling++;
|
||||
r->playerVote[member->GetGUID()] = NOT_EMITED_YET;
|
||||
vote = PASS;
|
||||
++r->totalPass;
|
||||
}
|
||||
r->playerVote[member->GetGUID()] = vote;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1154,20 +1177,21 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject)
|
||||
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* playerToRoll = itr->GetSource();
|
||||
if (!playerToRoll)
|
||||
if (!playerToRoll || !playerToRoll->GetSession())
|
||||
continue;
|
||||
|
||||
if (i->AllowedForPlayer(playerToRoll, loot->sourceWorldObjectGUID) && playerToRoll->IsAtLootRewardDistance(lootedObject))
|
||||
if (playerToRoll->IsAtGroupRewardDistance(lootedObject))
|
||||
{
|
||||
r->totalPlayersRolling++;
|
||||
if (playerToRoll->GetPassOnGroupLoot())
|
||||
|
||||
RollVote vote = playerToRoll->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET;
|
||||
if (!CanRollOnItem(*i, playerToRoll, loot))
|
||||
{
|
||||
r->playerVote[playerToRoll->GetGUID()] = PASS;
|
||||
r->totalPass++;
|
||||
// can't broadcast the pass now. need to wait until all rolling players are known.
|
||||
vote = PASS;
|
||||
r->totalPass++; // Can't broadcast the pass now. need to wait until all rolling players are known
|
||||
}
|
||||
else
|
||||
r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
|
||||
|
||||
r->playerVote[playerToRoll->GetGUID()] = vote;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1228,13 +1252,21 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject)
|
||||
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* playerToRoll = itr->GetSource();
|
||||
if (!playerToRoll)
|
||||
if (!playerToRoll || !playerToRoll->GetSession())
|
||||
continue;
|
||||
|
||||
if (i->AllowedForPlayer(playerToRoll, loot->sourceWorldObjectGUID) && playerToRoll->IsAtLootRewardDistance(lootedObject))
|
||||
if (playerToRoll->IsAtGroupRewardDistance(lootedObject))
|
||||
{
|
||||
r->totalPlayersRolling++;
|
||||
r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
|
||||
|
||||
RollVote vote = playerToRoll->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET;
|
||||
if (!CanRollOnItem(*i, playerToRoll, loot))
|
||||
{
|
||||
vote = PASS;
|
||||
r->totalPass++; // Can't broadcast the pass now. need to wait until all rolling players are known
|
||||
}
|
||||
|
||||
r->playerVote[playerToRoll->GetGUID()] = vote;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1996,6 +2028,35 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
|
||||
if (bgTemplate->isArena() && memberscount != MinPlayerCount)
|
||||
return ERR_ARENA_TEAM_PARTY_SIZE;
|
||||
|
||||
//check against other arena team members
|
||||
if (isRated)
|
||||
{
|
||||
ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId);
|
||||
for (auto const& itr : arenaTeam->GetMembers())
|
||||
{
|
||||
Player* teamMember = ObjectAccessor::FindConnectedPlayer(itr.Guid);
|
||||
//are they online and not a member of this current group?
|
||||
if (teamMember && !IsMember(teamMember->GetGUID()))
|
||||
{
|
||||
//are they already in queue for a rated arena?
|
||||
if (teamMember->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeId))
|
||||
{
|
||||
GroupQueueInfo ginfo;
|
||||
BattlegroundQueue& queue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
|
||||
if (queue.GetPlayerGroupInfoData(teamMember->GetGUID(), &ginfo))
|
||||
{
|
||||
if (ginfo.IsRated)
|
||||
return ERR_BATTLEGROUND_JOIN_FAILED;
|
||||
}
|
||||
}
|
||||
//are they currently in an arena match?
|
||||
Battleground* bg = teamMember->GetBattleground(false);
|
||||
if (bg && bg->isRated() && bg->GetMinPlayersPerTeam() == MinPlayerCount)
|
||||
return ERR_BATTLEGROUND_JOIN_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GroupJoinBattlegroundResult(bgTemplate->GetBgTypeID());
|
||||
}
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@ public:
|
||||
bool isRollLootActive() const;
|
||||
void SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll& r);
|
||||
void SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& r);
|
||||
void SendLootRoll(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll& r);
|
||||
void SendLootRoll(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll& r, bool autoPass = false);
|
||||
void SendLootRollWon(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll& r);
|
||||
void SendLootAllPassed(Roll const& roll);
|
||||
void SendLooter(Creature* creature, Player* pLooter);
|
||||
|
||||
@@ -889,6 +889,9 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
|
||||
pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation());
|
||||
else
|
||||
pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation());
|
||||
|
||||
// Probably a hackfix, but currently the best workaround to prevent character names showing as Unknown after teleport out from instances at login.
|
||||
pCurrChar->GetSession()->SendNameQueryOpcode(pCurrChar->GetGUID());
|
||||
}
|
||||
|
||||
pCurrChar->SendInitialPacketsAfterAddToMap();
|
||||
|
||||
@@ -283,14 +283,22 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
|
||||
if (msg.empty())
|
||||
return;
|
||||
|
||||
if (ChatHandler(this).ParseCommands(msg.c_str()))
|
||||
return;
|
||||
|
||||
if (!_player->CanSpeak())
|
||||
if (lang == LANG_ADDON)
|
||||
{
|
||||
std::string timeStr = secsToTimeString(m_muteTime - GameTime::GetGameTime().count());
|
||||
SendNotification(GetAcoreString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str());
|
||||
return;
|
||||
if (AddonChannelCommandHandler(this).ParseCommands(msg.c_str()))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ChatHandler(this).ParseCommands(msg.c_str()))
|
||||
return;
|
||||
|
||||
if (!_player->CanSpeak())
|
||||
{
|
||||
std::string timeStr = secsToTimeString(m_muteTime - GameTime::GetGameTime().count());
|
||||
SendNotification(GetAcoreString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,9 +84,12 @@ void WorldSession::HandleSetSheathedOpcode(WorldPackets::Combat::SetSheathed& pa
|
||||
|
||||
void WorldSession::SendAttackStop(Unit const* enemy)
|
||||
{
|
||||
WorldPacket data(SMSG_ATTACKSTOP, (8 + 8 + 4)); // we guess size
|
||||
WorldPacket data(SMSG_ATTACKSTOP, (8 + 8 + 4)); // we guess size
|
||||
data << GetPlayer()->GetPackGUID();
|
||||
data << (enemy ? enemy->GetPackGUID() : PackedGuid()); // must be packed guid
|
||||
data << uint32(0); // unk, can be 1 also
|
||||
if (enemy)
|
||||
{
|
||||
data << enemy->GetPackGUID(); // must be packed guid
|
||||
data << enemy->isDead();
|
||||
}
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
@@ -3069,7 +3069,7 @@ void InstanceMap::CreateInstanceScript(bool load, std::string data, uint32 compl
|
||||
|
||||
bool isOtherAI = false;
|
||||
|
||||
sScriptMgr->OnBeforeCreateInstanceScript(this, instance_data, load, data, completedEncounterMask);
|
||||
sScriptMgr->OnBeforeCreateInstanceScript(this, &instance_data, load, data, completedEncounterMask);
|
||||
|
||||
if (instance_data)
|
||||
isOtherAI = true;
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Define.h"
|
||||
#include "QuestDef.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ void ScriptMgr::OnMapUpdate(Map* map, uint32 diff)
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::OnBeforeCreateInstanceScript(InstanceMap* instanceMap, InstanceScript* instanceData, bool load, std::string data, uint32 completedEncounterMask)
|
||||
void ScriptMgr::OnBeforeCreateInstanceScript(InstanceMap* instanceMap, InstanceScript** instanceData, bool load, std::string data, uint32 completedEncounterMask)
|
||||
{
|
||||
ExecuteScript<AllMapScript>([&](AllMapScript* script)
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
* @param data Contains information about the instance save data
|
||||
* @param completedEncounterMask Contains information about the completed encouter mask
|
||||
*/
|
||||
virtual void OnBeforeCreateInstanceScript(InstanceMap* /*instanceMap*/, InstanceScript* /*instanceData*/, bool /*load*/, std::string /*data*/, uint32 /*completedEncounterMask*/) { }
|
||||
virtual void OnBeforeCreateInstanceScript(InstanceMap* /*instanceMap*/, InstanceScript** /*instanceData*/, bool /*load*/, std::string /*data*/, uint32 /*completedEncounterMask*/) { }
|
||||
|
||||
/**
|
||||
* @brief This hook called before destroy instance
|
||||
|
||||
@@ -605,7 +605,7 @@ public: /* AllGameobjectScript */
|
||||
void OnGameObjectSaveToDB(GameObject* go);
|
||||
|
||||
public: /* AllMapScript */
|
||||
void OnBeforeCreateInstanceScript(InstanceMap* instanceMap, InstanceScript* instanceData, bool load, std::string data, uint32 completedEncounterMask);
|
||||
void OnBeforeCreateInstanceScript(InstanceMap* instanceMap, InstanceScript** instanceData, bool load, std::string data, uint32 completedEncounterMask);
|
||||
void OnDestroyInstance(MapInstanced* mapInstanced, Map* map);
|
||||
|
||||
public: /* BGScript */
|
||||
|
||||
@@ -2011,7 +2011,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
if (modelid > 0)
|
||||
{
|
||||
bool allow = true;
|
||||
if (target->getTransForm())
|
||||
if (target->getTransForm() && !(target->GetMapId() == 560 /*The Escape From Durnholde*/))
|
||||
if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm()))
|
||||
if (transformSpellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || !transformSpellInfo->IsPositive())
|
||||
allow = false;
|
||||
@@ -2143,7 +2143,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
SpellShapeshiftEntry const* shapeInfo = sSpellShapeshiftStore.LookupEntry(form);
|
||||
SpellShapeshiftFormEntry const* shapeInfo = sSpellShapeshiftFormStore.LookupEntry(form);
|
||||
// Learn spells for shapeshift form - no need to send action bars or add spells to spellbook
|
||||
for (uint8 i = 0; i < MAX_SHAPESHIFT_SPELLS; ++i)
|
||||
{
|
||||
|
||||
@@ -5799,7 +5799,7 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
SpellEffectInfo const* effInfo = &m_spellInfo->Effects[effIndex];
|
||||
if (effInfo->ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT)
|
||||
{
|
||||
SpellShapeshiftEntry const* shapeShiftEntry = sSpellShapeshiftStore.LookupEntry(effInfo->MiscValue);
|
||||
SpellShapeshiftFormEntry const* shapeShiftEntry = sSpellShapeshiftFormStore.LookupEntry(effInfo->MiscValue);
|
||||
if (shapeShiftEntry && (shapeShiftEntry->flags1 & 1) == 0) // unk flag
|
||||
checkMask |= VEHICLE_SEAT_FLAG_UNCONTROLLED;
|
||||
break;
|
||||
|
||||
@@ -1435,10 +1435,10 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
bool actAsShifted = false;
|
||||
SpellShapeshiftEntry const* shapeInfo = nullptr;
|
||||
SpellShapeshiftFormEntry const* shapeInfo = nullptr;
|
||||
if (form > 0)
|
||||
{
|
||||
shapeInfo = sSpellShapeshiftStore.LookupEntry(form);
|
||||
shapeInfo = sSpellShapeshiftFormStore.LookupEntry(form);
|
||||
if (!shapeInfo)
|
||||
{
|
||||
LOG_ERROR("spells", "GetErrorAtShapeshiftedCast: unknown shapeshift {}", form);
|
||||
@@ -2437,7 +2437,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
if (AttributesEx4 & SPELL_ATTR4_WEAPON_SPEED_COST_SCALING)
|
||||
{
|
||||
uint32 speed = 0;
|
||||
if (SpellShapeshiftEntry const* ss = sSpellShapeshiftStore.LookupEntry(caster->GetShapeshiftForm()))
|
||||
if (SpellShapeshiftFormEntry const* ss = sSpellShapeshiftFormStore.LookupEntry(caster->GetShapeshiftForm()))
|
||||
speed = ss->attackSpeed;
|
||||
else
|
||||
{
|
||||
|
||||
@@ -165,10 +165,11 @@ void WorldUpdateTime::RecordUpdateTime(Milliseconds gameTimeMs, uint32 diff, uin
|
||||
{
|
||||
if (GetMSTimeDiff(_lastRecordTime, gameTimeMs) > _recordUpdateTimeInverval)
|
||||
{
|
||||
LOG_INFO("time.update", "Last {} diffs summary with {} players online:", GetDatasetSize(), sessionCount);
|
||||
LOG_INFO("time.update", " - Mean: {};", GetAverageUpdateTime());
|
||||
LOG_INFO("time.update", " - Median: {};", GetPercentile(50));
|
||||
LOG_INFO("time.update", " - Percentiles (95, 99, max): {}, {}, {}.", GetPercentile(95), GetPercentile(99), GetPercentile(100));
|
||||
LOG_INFO("time.update", "Update time diff: {}ms with {} players online", GetLastUpdateTime(), sessionCount);
|
||||
LOG_INFO("time.update", "Last {} diffs summary:", GetDatasetSize());
|
||||
LOG_INFO("time.update", "|- Mean: {}ms", GetAverageUpdateTime());
|
||||
LOG_INFO("time.update", "|- Median: {}ms", GetPercentile(50));
|
||||
LOG_INFO("time.update", "|- Percentiles (95, 99, max): {}ms, {}ms, {}ms", GetPercentile(95), GetPercentile(99), GetPercentile(100));
|
||||
_lastRecordTime = gameTimeMs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Acore::Impl::EnumUtilsImpl
|
||||
|
||||
Reference in New Issue
Block a user