Merge branch 'master' into Playerbot

# Conflicts:
#	src/server/game/Entities/Player/Player.cpp
#	src/server/game/Entities/Player/Player.h
#	src/server/game/Entities/Unit/Unit.h
This commit is contained in:
郑佩茹
2022-08-16 16:13:26 -06:00
159 changed files with 5246 additions and 2794 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ int32 NullCreatureAI::Permissible(Creature const* creature)
return PERMIT_BASE_PROACTIVE + 50;
if (creature->IsTrigger())
return PERMIT_BASE_REACTIVE;
return PERMIT_BASE_PROACTIVE;
return PERMIT_BASE_IDLE;
}
+26
View File
@@ -90,6 +90,24 @@ bool UnitAI::DoSpellAttackIfReady(uint32 spell)
return false;
}
void UnitAI::DoSpellAttackToRandomTargetIfReady(uint32 spell, uint32 threatTablePosition /*= 0*/, float dist /*= 0.f*/, bool playerOnly /*= true*/)
{
if (me->HasUnitState(UNIT_STATE_CASTING) || !me->isAttackReady())
return;
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell))
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, threatTablePosition, dist, playerOnly))
{
if (me->IsWithinCombatRange(target, spellInfo->GetMaxRange(false)))
{
me->CastSpell(target, spell, false);
me->resetAttackTimer();
}
}
}
}
Unit* UnitAI::SelectTarget(SelectTargetMethod targetType, uint32 position, float dist, bool playerOnly, int32 aura)
{
return SelectTarget(targetType, position, DefaultTargetSelector(me, dist, playerOnly, aura));
@@ -106,6 +124,14 @@ float UnitAI::DoGetSpellMaxRange(uint32 spellId, bool positive)
return spellInfo ? spellInfo->GetMaxRange(positive) : 0;
}
std::string UnitAI::GetDebugInfo() const
{
std::stringstream sstr;
sstr << std::boolalpha
<< "Me: " << (me ? me->GetDebugInfo() : "NULL");
return sstr.str();
}
SpellCastResult UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid)
{
if (me->IsInCombat())
+3
View File
@@ -330,6 +330,7 @@ public:
void DoMeleeAttackIfReady();
bool DoSpellAttackIfReady(uint32 spell);
void DoSpellAttackToRandomTargetIfReady(uint32 spell, uint32 threatTablePosition = 0, float dist = 0.f, bool playerOnly = true);
static AISpellInfoType* AISpellInfo;
static void FillAISpellInfo();
@@ -345,6 +346,8 @@ public:
virtual void sQuestComplete(Player* /*player*/, Quest const* /*quest*/) {}
virtual void sQuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) {}
virtual void sOnGameEvent(bool /*start*/, uint16 /*eventId*/) {}
virtual std::string GetDebugInfo() const;
};
class PlayerAI : public UnitAI
@@ -917,7 +917,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (IsUnit(target))
{
float angle = e.action.follow.angle > 6 ? (e.action.follow.angle * M_PI / 180.0f) : e.action.follow.angle;
CAST_AI(SmartAI, me->AI())->SetFollow(target->ToUnit(), float(e.action.follow.dist) + 0.1f, angle, e.action.follow.credit, e.action.follow.entry, e.action.follow.creditType);
CAST_AI(SmartAI, me->AI())->SetFollow(target->ToUnit(), float(e.action.follow.dist) + 0.1f, angle, e.action.follow.credit, e.action.follow.entry, e.action.follow.creditType, e.action.follow.aliveState);
LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_FOLLOW: Creature {} following target {}",
me->GetGUID().ToString(), target->GetGUID().ToString());
break;
@@ -3187,6 +3187,10 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
{
targets.push_back(owner);
}
else if (me->IsSummon() && me->ToTempSummon()->GetSummonerUnit())
{
targets.push_back(me->ToTempSummon()->GetSummonerUnit());
}
}
else if (go)
{
@@ -492,7 +492,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
case SMART_EVENT_IC_LOS: return sizeof(SmartEvent::los);
case SMART_EVENT_PASSENGER_BOARDED: return sizeof(SmartEvent::minMax);
case SMART_EVENT_PASSENGER_REMOVED: return sizeof(SmartEvent::minMax);
// case SMART_EVENT_CHARMED: return sizeof(SmartEvent::charm);
case SMART_EVENT_CHARMED: return sizeof(SmartEvent::charm);
case SMART_EVENT_CHARMED_TARGET: return NO_PARAMS;
case SMART_EVENT_SPELLHIT_TARGET: return sizeof(SmartEvent::spellHit);
case SMART_EVENT_DAMAGED: return sizeof(SmartEvent::minMaxRepeat);
@@ -533,7 +533,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
case SMART_EVENT_IS_BEHIND_TARGET: return sizeof(SmartEvent::behindTarget);
case SMART_EVENT_GAME_EVENT_START: return sizeof(SmartEvent::gameEvent);
case SMART_EVENT_GAME_EVENT_END: return sizeof(SmartEvent::gameEvent);
// case SMART_EVENT_GO_LOOT_STATE_CHANGED: return sizeof(SmartEvent::goLootStateChanged);
case SMART_EVENT_GO_STATE_CHANGED: return sizeof(SmartEvent::goStateChanged);
case SMART_EVENT_GO_EVENT_INFORM: return sizeof(SmartEvent::eventInform);
case SMART_EVENT_ACTION_DONE: return sizeof(SmartEvent::doAction);
case SMART_EVENT_ON_SPELLCLICK: return NO_PARAMS;
@@ -546,9 +546,11 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
//case SMART_EVENT_SCENE_CANCEL: return sizeof(SmartEvent::raw);
//case SMART_EVENT_SCENE_COMPLETE: return sizeof(SmartEvent::raw);
case SMART_EVENT_SUMMONED_UNIT_DIES: return sizeof(SmartEvent::summoned);
case SMART_EVENT_NEAR_PLAYERS: return sizeof(SmartEvent::nearPlayer);
case SMART_EVENT_NEAR_PLAYERS_NEGATION: return sizeof(SmartEvent::nearPlayerNegation);
default:
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an event with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an event {} with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetEventType());
return sizeof(SmartEvent::raw);
}
}();
@@ -602,8 +604,8 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_ALLOW_COMBAT_MOVEMENT: return sizeof(SmartAction::combatMove);
case SMART_ACTION_SET_EVENT_PHASE: return sizeof(SmartAction::setEventPhase);
case SMART_ACTION_INC_EVENT_PHASE: return sizeof(SmartAction::incEventPhase);
// case SMART_ACTION_EVADE: return sizeof(SmartAction::evade);
// case SMART_ACTION_FLEE_FOR_ASSIST: return sizeof(SmartAction::fleeAssist);
case SMART_ACTION_EVADE: return NO_PARAMS;
case SMART_ACTION_FLEE_FOR_ASSIST: return sizeof(SmartAction::flee);
case SMART_ACTION_CALL_GROUPEVENTHAPPENS: return sizeof(SmartAction::quest);
case SMART_ACTION_COMBAT_STOP: return NO_PARAMS;
case SMART_ACTION_REMOVEAURASFROMSPELL: return sizeof(SmartAction::removeAura);
@@ -624,9 +626,10 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL: return sizeof(SmartAction::morphOrMount);
case SMART_ACTION_SET_INGAME_PHASE_MASK: return sizeof(SmartAction::ingamePhaseMask);
case SMART_ACTION_SET_DATA: return sizeof(SmartAction::setData);
case SMART_ACTION_MOVE_FORWARD: return sizeof(SmartAction::moveRandom);
case SMART_ACTION_ATTACK_STOP: return NO_PARAMS;
case SMART_ACTION_SET_VISIBILITY: return sizeof(SmartAction::visibility);
// case SMART_ACTION_SET_ACTIVE: return sizeof(SmartAction::active);
case SMART_ACTION_SET_ACTIVE: return sizeof(SmartAction::setActive);
case SMART_ACTION_ATTACK_START: return NO_PARAMS;
case SMART_ACTION_SUMMON_GO: return sizeof(SmartAction::summonGO);
case SMART_ACTION_KILL_UNIT: return NO_PARAMS;
@@ -638,7 +641,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_REMOVE_ITEM: return sizeof(SmartAction::item);
case SMART_ACTION_INSTALL_AI_TEMPLATE: return sizeof(SmartAction::installTtemplate);
case SMART_ACTION_SET_RUN: return sizeof(SmartAction::setRun);
// case SMART_ACTION_SET_DISABLE_GRAVITY: return sizeof(SmartAction::setDisableGravity);
case SMART_ACTION_SET_FLY: return sizeof(SmartAction::setFly);
case SMART_ACTION_SET_SWIM: return sizeof(SmartAction::setSwim);
case SMART_ACTION_TELEPORT: return sizeof(SmartAction::teleport);
case SMART_ACTION_SET_COUNTER: return sizeof(SmartAction::setCounter);
@@ -648,7 +651,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_CREATE_TIMED_EVENT: return sizeof(SmartAction::timeEvent);
case SMART_ACTION_PLAYMOVIE: return sizeof(SmartAction::movie);
case SMART_ACTION_MOVE_TO_POS: return sizeof(SmartAction::moveToPos);
// case SMART_ACTION_ENABLE_TEMP_GOBJ: return sizeof(SmartAction::enableTempGO);
case SMART_ACTION_RESPAWN_TARGET: return sizeof(SmartAction::RespawnTarget);
case SMART_ACTION_EQUIP: return sizeof(SmartAction::equip);
case SMART_ACTION_CLOSE_GOSSIP: return NO_PARAMS;
case SMART_ACTION_TRIGGER_TIMED_EVENT: return sizeof(SmartAction::timeEvent);
@@ -663,7 +666,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_ADD_NPC_FLAG: return sizeof(SmartAction::flag);
case SMART_ACTION_REMOVE_NPC_FLAG: return sizeof(SmartAction::flag);
case SMART_ACTION_SIMPLE_TALK: return sizeof(SmartAction::simpleTalk);
// case SMART_ACTION_SELF_CAST: return sizeof(SmartAction::cast);
case SMART_ACTION_INVOKER_CAST: return sizeof(SmartAction::cast);
case SMART_ACTION_CROSS_CAST: return sizeof(SmartAction::crossCast);
case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: return sizeof(SmartAction::randTimedActionList);
case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: return sizeof(SmartAction::randRangeTimedActionList);
@@ -692,7 +695,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_GAME_EVENT_STOP: return sizeof(SmartAction::gameEventStop);
case SMART_ACTION_GAME_EVENT_START: return sizeof(SmartAction::gameEventStart);
case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::closestWaypointFromList);
// case SMART_ACTION_MOVE_OFFSET: return NO_PARAMS;
case SMART_ACTION_RISE_UP: return sizeof(SmartAction::moveRandom);
case SMART_ACTION_RANDOM_SOUND: return sizeof(SmartAction::randomSound);
case SMART_ACTION_SET_CORPSE_DELAY: return sizeof(SmartAction::corpseDelay);
case SMART_ACTION_DISABLE_EVADE: return sizeof(SmartAction::disableEvade);
@@ -722,6 +725,19 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_SET_HOVER: return sizeof(SmartAction::setHover);
case SMART_ACTION_SET_HEALTH_PCT: return sizeof(SmartAction::setHealthPct);
//case SMART_ACTION_CREATE_CONVERSATION: return sizeof(SmartAction::raw);
case SMART_ACTION_MOVE_TO_POS_TARGET: return sizeof(SmartAction::moveToPos);
case SMART_ACTION_SET_GO_STATE: return sizeof(SmartAction::goState);
case SMART_ACTION_EXIT_VEHICLE: return NO_PARAMS;
case SMART_ACTION_SET_UNIT_MOVEMENT_FLAGS: return sizeof(SmartAction::movementFlag);
case SMART_ACTION_SET_COMBAT_DISTANCE: return sizeof(SmartAction::combatDistance);
case SMART_ACTION_SET_CASTER_COMBAT_DIST: return sizeof(SmartAction::casterDistance);
case SMART_ACTION_FALL: return NO_PARAMS;
case SMART_ACTION_SET_EVENT_FLAG_RESET: return sizeof(SmartAction::setActive);
case SMART_ACTION_STOP_MOTION: return sizeof(SmartAction::stopMotion);
case SMART_ACTION_NO_ENVIRONMENT_UPDATE: return NO_PARAMS;
case SMART_ACTION_ZONE_UNDER_ATTACK: return NO_PARAMS;
case SMART_ACTION_LOAD_GRID: return NO_PARAMS;
case SMART_ACTION_MUSIC: return sizeof(SmartAction::music);
default:
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -785,9 +801,10 @@ bool SmartAIMgr::CheckUnusedTargetParams(SmartScriptHolder const& e)
case SMART_TARGET_FARTHEST: return sizeof(SmartTarget::farthest);
case SMART_TARGET_VEHICLE_PASSENGER: return sizeof(SmartTarget::vehicle);
// case SMART_TARGET_CLOSEST_UNSPAWNED_GAMEOBJECT: return sizeof(SmartTarget::goClosest);
case SMART_TARGET_PLAYER_WITH_AURA: return sizeof(SmartTarget::playerWithAura);
default:
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using a target with no unused params specified in SmartAIMgr::CheckUnusedTargetParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using a target {} with no unused params specified in SmartAIMgr::CheckUnusedTargetParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
return sizeof(SmartTarget::raw);
}
}();
@@ -86,28 +86,29 @@ bool BattlegroundQueue::SelectionPool::KickGroup(const uint32 size)
// find last group with proper size or largest
bool foundProper = false;
auto groupToKick = SelectedGroups.begin();
for (auto& itr = groupToKick; itr != SelectedGroups.end(); ++itr)
GroupQueueInfo* groupToKick{ SelectedGroups.front() };
for (auto const& gInfo : SelectedGroups)
{
// if proper size - overwrite to kick last one
if (std::abs(int32((*itr)->Players.size()) - (int32)size) <= 1)
if (std::abs(int32(gInfo->Players.size()) - (int32)size) <= 1)
{
groupToKick = itr;
groupToKick = gInfo;
foundProper = true;
}
else if (!foundProper && (*itr)->Players.size() >= (*groupToKick)->Players.size())
groupToKick = itr;
else if (!foundProper && gInfo->Players.size() >= groupToKick->Players.size())
groupToKick = gInfo;
}
// remove selected from pool
GroupQueueInfo* ginfo = (*groupToKick);
SelectedGroups.erase(groupToKick);
PlayerCount -= ginfo->Players.size();
auto playersCountInGroup{ groupToKick->Players.size() };
PlayerCount -= playersCountInGroup;
std::erase(SelectedGroups, groupToKick);
if (foundProper)
return false;
return (ginfo->Players.size() > size);
return playersCountInGroup > size;
}
// returns true if added or desired count not yet reached
+5 -5
View File
@@ -565,11 +565,11 @@ void LoadDBCStores(const std::string& dataPath)
if (sInfo->Effect[j] == SPELL_EFFECT_SEND_TAXI)
spellPaths.insert(sInfo->EffectMiscValue[j]);
memset(sTaxiNodesMask, 0, sizeof(sTaxiNodesMask));
memset(sOldContinentsNodesMask, 0, sizeof(sOldContinentsNodesMask));
memset(sHordeTaxiNodesMask, 0, sizeof(sHordeTaxiNodesMask));
memset(sAllianceTaxiNodesMask, 0, sizeof(sAllianceTaxiNodesMask));
memset(sDeathKnightTaxiNodesMask, 0, sizeof(sDeathKnightTaxiNodesMask));
sTaxiNodesMask.fill(0);
sOldContinentsNodesMask.fill(0);
sHordeTaxiNodesMask.fill(0);
sAllianceTaxiNodesMask.fill(0);
sDeathKnightTaxiNodesMask.fill(0);
for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
{
@@ -3656,3 +3656,12 @@ uint32 Creature::GetPlayerDamageReq() const
{
return _playerDamageReq;
}
std::string Creature::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Unit::GetDebugInfo() << "\n"
<< "AIName: " << GetAIName() << " ScriptName: " << GetScriptName()
<< " WaypointPath: " << GetWaypointPath() << " SpawnId: " << GetSpawnId();
return sstr.str();
}
@@ -385,6 +385,8 @@ public:
void ModifyThreatPercentTemp(Unit* victim, int32 percent, Milliseconds duration);
std::string GetDebugInfo() const override;
protected:
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 Entry, uint32 vehId, const CreatureData* data = nullptr);
bool InitEntry(uint32 entry, const CreatureData* data = nullptr);
@@ -320,6 +320,15 @@ void TempSummon::RemoveFromWorld()
Creature::RemoveFromWorld();
}
std::string TempSummon::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Creature::GetDebugInfo() << "\n"
<< std::boolalpha
<< "TempSummonType : " << std::to_string(GetSummonType()) << " Summoner: " << GetSummonerGUID().ToString();
return sstr.str();
}
Minion::Minion(SummonPropertiesEntry const* properties, ObjectGuid owner, bool isWorldObject) : TempSummon(properties, owner, isWorldObject)
, m_owner(owner)
{
@@ -378,6 +387,15 @@ void Minion::setDeathState(DeathState s, bool despawn)
}
}
std::string Minion::GetDebugInfo() const
{
std::stringstream sstr;
sstr << TempSummon::GetDebugInfo() << "\n"
<< std::boolalpha
<< "Owner: " << (GetOwner() ? GetOwner()->GetGUID().ToString() : "");
return sstr.str();
}
Guardian::Guardian(SummonPropertiesEntry const* properties, ObjectGuid owner, bool isWorldObject) : Minion(properties, owner, isWorldObject)
{
m_unitTypeMask |= UNIT_MASK_GUARDIAN;
@@ -416,6 +434,13 @@ void Guardian::InitSummon()
}
}
std::string Guardian::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Minion::GetDebugInfo();
return sstr.str();
}
Puppet::Puppet(SummonPropertiesEntry const* properties, ObjectGuid owner) : Minion(properties, owner, false), m_owner(owner) //maybe true?
{
ASSERT(owner.IsPlayer());
@@ -52,12 +52,14 @@ public:
[[nodiscard]] Unit* GetSummonerUnit() const;
[[nodiscard]] Creature* GetSummonerCreatureBase() const;
[[nodiscard]] GameObject* GetSummonerGameObject() const;
ObjectGuid GetSummonerGUID() { return m_summonerGUID; }
TempSummonType const& GetSummonType() { return m_type; }
ObjectGuid GetSummonerGUID() const { return m_summonerGUID; }
TempSummonType GetSummonType() const { return m_type; }
uint32 GetTimer() { return m_timer; }
void SetTimer(uint32 t) { m_timer = t; }
const SummonPropertiesEntry* const m_Properties;
std::string GetDebugInfo() const override;
private:
TempSummonType m_type;
uint32 m_timer;
@@ -77,6 +79,8 @@ public:
[[nodiscard]] bool IsPetGhoul() const {return GetEntry() == 26125 /*normal ghoul*/ || GetEntry() == 30230 /*Raise Ally ghoul*/;} // Ghoul may be guardian or pet
[[nodiscard]] bool IsGuardianPet() const;
void setDeathState(DeathState s, bool despawn = false) override; // override virtual Unit::setDeathState
std::string GetDebugInfo() const override;
protected:
const ObjectGuid m_owner;
float m_followAngle;
@@ -97,6 +101,8 @@ public:
void UpdateMaxPower(Powers power) override;
void UpdateAttackPowerAndDamage(bool ranged = false) override;
void UpdateDamagePhysical(WeaponAttackType attType) override;
std::string GetDebugInfo() const override;
};
class Puppet : public Minion
@@ -131,7 +131,7 @@ void GameObject::RemoveFromOwner()
return;
}
LOG_FATAL("entities.gameobject", "Delete GameObject ({} Entry: {} SpellId {} LinkedGO {}) that lost references to owner {} GO list. Crash possible later.",
LOG_DEBUG("entities.gameobject", "Delete GameObject ({} Entry: {} SpellId {} LinkedGO {}) that lost references to owner {} GO list.",
GetGUID().ToString(), GetGOInfo()->entry, m_spellId, GetGOInfo()->GetLinkedGameObjectEntry(), ownerGUID.ToString());
SetOwnerGUID(ObjectGuid::Empty);
@@ -3091,3 +3091,11 @@ bool GameObject::IsInSkillupList(ObjectGuid playerGuid) const
return false;
}
std::string GameObject::GetDebugInfo() const
{
std::stringstream sstr;
sstr << WorldObject::GetDebugInfo() << "\n"
<< "SpawnId: " << GetSpawnId() << " GoState: " << std::to_string(GetGoState()) << " ScriptId: " << GetScriptId() << " AIName: " << GetAIName();
return sstr.str();
}
@@ -1061,6 +1061,8 @@ public:
void UpdateSaveToDb(bool enable);
void SavingStateOnDB();
std::string GetDebugInfo() const override;
protected:
bool AIM_Initialize();
GameObjectModel* CreateModel();
@@ -239,3 +239,10 @@ Item* Bag::GetItemByPos(uint8 slot) const
return nullptr;
}
std::string Bag::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Item::GetDebugInfo();
return sstr.str();
}
@@ -35,7 +35,6 @@ public:
bool Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner) override;
void Clear();
void StoreItem(uint8 slot, Item* pItem, bool update);
void RemoveItem(uint8 slot, bool update);
@@ -58,6 +57,8 @@ public:
void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override;
std::string GetDebugInfo() const override;
protected:
// Bag Storage space
Item* m_bagslot[MAX_BAG_SIZE];
+11 -1
View File
@@ -1097,7 +1097,7 @@ Item* Item::CreateItem(uint32 item, uint32 count, Player const* player, bool clo
if (count > pProto->GetMaxStackSize())
count = pProto->GetMaxStackSize();
ASSERT(count != 0 && "pProto->Stackable == 0 but checked at loading already");
ASSERT_NODEBUGINFO(count != 0 && "pProto->Stackable == 0 but checked at loading already");
Item* pItem = NewItemOrBag(pProto);
if (pItem->Create(sObjectMgr->GetGenerator<HighGuid::Item>().Generate(), item, player))
@@ -1287,3 +1287,13 @@ bool Item::CheckSoulboundTradeExpire()
return false;
}
std::string Item::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Object::GetDebugInfo() << "\n"
<< std::boolalpha
<< "Owner: " << GetOwnerGUID().ToString() << " Count: " << GetCount()
<< " BagSlot: " << std::to_string(GetBagSlot()) << " Slot: " << std::to_string(GetSlot()) << " Equipped: " << IsEquipped();
return sstr.str();
}
+2
View File
@@ -353,6 +353,8 @@ public:
void RemoveFromObjectUpdate() override;
[[nodiscard]] uint32 GetScriptId() const { return GetTemplate()->ScriptId; }
std::string GetDebugInfo() const override;
private:
std::string m_text;
uint8 m_slot;
@@ -1010,6 +1010,13 @@ bool Object::PrintIndexError(uint32 index, bool set) const
return false;
}
std::string Object::GetDebugInfo() const
{
std::stringstream sstr;
sstr << GetGUID().ToString() + " Entry " << GetEntry();
return sstr.str();
}
void MovementInfo::OutDebug()
{
LOG_INFO("movement", "MOVEMENT INFO");
@@ -2419,6 +2426,15 @@ Player* WorldObject::SelectNearestPlayer(float distance) const
return target;
}
std::string WorldObject::GetDebugInfo() const
{
std::stringstream sstr;
sstr << WorldLocation::GetDebugInfo() << "\n"
<< Object::GetDebugInfo() << "\n"
<< "Name: " << GetName();
return sstr.str();
}
void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>& gameobjectList, uint32 entry, float maxSearchRange) const
{
Acore::AllGameObjectsWithEntryInRange check(this, entry, maxSearchRange);
+4
View File
@@ -208,6 +208,8 @@ public:
DynamicObject* ToDynObject() { if (GetTypeId() == TYPEID_DYNAMICOBJECT) return reinterpret_cast<DynamicObject*>(this); else return nullptr; }
[[nodiscard]] DynamicObject const* ToDynObject() const { if (GetTypeId() == TYPEID_DYNAMICOBJECT) return reinterpret_cast<DynamicObject const*>(this); else return nullptr; }
virtual std::string GetDebugInfo() const;
DataMap CustomData;
protected:
@@ -613,6 +615,8 @@ public:
[[nodiscard]] bool HasAllowedLooter(ObjectGuid guid) const;
[[nodiscard]] GuidUnorderedSet const& GetAllowedLooters() const;
std::string GetDebugInfo() const override;
ElunaEventProcessor* elunaEvents;
protected:
@@ -208,3 +208,10 @@ ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& st
buf << x << y << z << o;
return buf;
}
std::string WorldLocation::GetDebugInfo() const
{
std::stringstream sstr;
sstr << "MapID: " << m_mapId << " " << Position::ToString();
return sstr.str();
}
@@ -317,6 +317,8 @@ public:
}
uint32 m_mapId;
std::string GetDebugInfo() const;
};
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
+10
View File
@@ -2439,3 +2439,13 @@ std::string Pet::GenerateActionBarData() const
return oss.str();
}
std::string Pet::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Guardian::GetDebugInfo() << "\n"
<< std::boolalpha
<< "PetType: " << std::to_string(getPetType()) << " "
<< "PetNumber: " << m_charmInfo->GetPetNumber();
return sstr.str();
}
+2
View File
@@ -143,6 +143,8 @@ public:
void SetLoading(bool load) { m_loading = load; }
[[nodiscard]] bool HasTempSpell() const { return m_tempspell != 0; }
std::string GetDebugInfo() const override;
protected:
Player* m_owner;
int32 m_happinessTimer;
+92 -63
View File
@@ -222,6 +222,7 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
m_bHasDelayedTeleport = false;
teleportStore_options = 0;
m_canTeleport = false;
m_canKnockback = false;
m_trade = nullptr;
@@ -1644,10 +1645,8 @@ void Player::ProcessDelayedOperations()
{
if (m_entryPointData.HasTaxiPath())
{
for (size_t i = 0; i < m_entryPointData.taxiPath.size() - 1; ++i)
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[i]);
m_taxi.SetTaxiSegment(m_entryPointData.taxiPath[m_entryPointData.taxiPath.size() - 1]);
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[0]);
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[1]);
m_entryPointData.ClearTaxiPath();
ContinueTaxiFlight();
}
@@ -10004,26 +10003,6 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
return false;
}
// check node starting pos data set case if provided
if (node->x != 0.0f || node->y != 0.0f || node->z != 0.0f)
{
if (node->map_id != GetMapId() ||
(node->x - GetPositionX()) * (node->x - GetPositionX()) +
(node->y - GetPositionY()) * (node->y - GetPositionY()) +
(node->z - GetPositionZ()) * (node->z - GetPositionZ()) >
(2 * INTERACTION_DISTANCE) * (2 * INTERACTION_DISTANCE) * (2 * INTERACTION_DISTANCE))
{
GetSession()->SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
return false;
}
}
// node must have pos if taxi master case (npc != nullptr)
else if (npc)
{
GetSession()->SendActivateTaxiReply(ERR_TAXIUNSPECIFIEDSERVERERROR);
return false;
}
// Prepare to flight start now
// stop combat at start taxi flight if any
@@ -10045,6 +10024,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
// fill destinations path tail
uint32 sourcepath = 0;
uint32 totalcost = 0;
uint32 firstcost = 0;
uint32 prevnode = sourcenode;
uint32 lastnode = 0;
@@ -10063,6 +10043,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
}
totalcost += cost;
if (i == 1)
firstcost = cost;
if (prevnode == sourcenode)
sourcepath = path;
@@ -10091,7 +10073,16 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
uint32 money = GetMoney();
if (npc)
totalcost = (uint32)ceil(totalcost * GetReputationPriceDiscount(npc));
{
float discount = GetReputationPriceDiscount(npc);
totalcost = uint32(ceil(totalcost * discount));
firstcost = uint32(ceil(firstcost * discount));
m_taxi.SetFlightMasterFactionTemplateId(npc->GetFaction());
}
else
{
m_taxi.SetFlightMasterFactionTemplateId(0);
}
if (money < totalcost)
{
@@ -10102,8 +10093,6 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
//Checks and preparations done, DO FLIGHT
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1);
ModifyMoney(-(int32)totalcost);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost);
// prevent stealth flight
//RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
@@ -10113,12 +10102,16 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
{
TaxiNodesEntry const* lastPathNode = sTaxiNodesStore.LookupEntry(nodes[nodes.size() - 1]);
m_taxi.ClearTaxiDestinations();
ModifyMoney(-(int32)totalcost);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost);
TeleportTo(lastPathNode->map_id, lastPathNode->x, lastPathNode->y, lastPathNode->z, GetOrientation());
return false;
}
else
{
m_flightSpellActivated = spellid;
ModifyMoney(-(int32)firstcost);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, firstcost);
GetSession()->SendActivateTaxiReply(ERR_TAXIOK);
GetSession()->SendDoFlight(mount_display_id, sourcepath);
}
@@ -10214,6 +10207,39 @@ void Player::ContinueTaxiFlight()
GetSession()->SendDoFlight(mountDisplayId, path, startNode);
}
void Player::SendTaxiNodeStatusMultiple()
{
for (auto itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
{
if (!itr->IsCreature())
{
continue;
}
Creature* creature = ObjectAccessor::GetCreature(*this, *itr);
if (!creature || creature->IsHostileTo(this))
{
continue;
}
if (!creature->HasNpcFlag(UNIT_NPC_FLAG_FLIGHTMASTER))
{
continue;
}
uint32 nearestNode = sObjectMgr->GetNearestTaxiNode(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetMapId(), GetTeamId());
if (!nearestNode)
{
continue;
}
WorldPacket data(SMSG_TAXINODE_STATUS, 9);
data << *itr;
data << uint8(m_taxi.IsTaximaskNodeKnown(nearestNode) ? 1 : 0);
SendDirectMessage(&data);
}
}
void Player::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
{
PacketCooldowns cooldowns;
@@ -10984,11 +11010,8 @@ void Player::SetEntryPoint()
m_entryPointData.mountSpell = 0;
m_entryPointData.joinPos = WorldLocation(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
std::vector<uint32> const& taxi = m_taxi.GetPath();
for (std::vector<uint32>::const_iterator itr = taxi.begin(); itr != taxi.end(); ++itr)
m_entryPointData.taxiPath.push_back(*itr);
m_entryPointData.taxiPath.push_back(m_taxi.GetTaxiSegment());
m_entryPointData.taxiPath[0] = m_taxi.GetTaxiSource();
m_entryPointData.taxiPath[1] = m_taxi.GetTaxiDestination();
}
else
{
@@ -11353,6 +11376,7 @@ void Player::SendInitialPacketsAfterAddToMap()
SendEnchantmentDurations(); // must be after add to map
SendItemDurations(); // must be after add to map
SendQuestGiverStatusMultiple();
SendTaxiNodeStatusMultiple();
// raid downscaling - send difficulty to player
if (GetMap()->IsRaid())
@@ -12007,23 +12031,21 @@ bool Player::GetBGAccessByLevel(BattlegroundTypeId bgTypeId) const
float Player::GetReputationPriceDiscount(Creature const* creature) const
{
FactionTemplateEntry const* vendorFaction = creature->GetFactionTemplateEntry();
if (!vendorFaction)
return GetReputationPriceDiscount(creature->GetFactionTemplateEntry());
}
float Player::GetReputationPriceDiscount(FactionTemplateEntry const* factionTemplate) const
{
if (!factionTemplate || !factionTemplate->faction)
{
return 1.0f;
}
return GetReputationPriceDiscount(vendorFaction);
}
float Player::GetReputationPriceDiscount(FactionTemplateEntry const* vendorFaction) const
{
if (!vendorFaction->faction)
return 1.0f;
ReputationRank rank = GetReputationRank(vendorFaction->faction);
ReputationRank rank = GetReputationRank(factionTemplate->faction);
if (rank <= REP_NEUTRAL)
{
return 1.0f;
}
return 1.0f - 0.05f * (rank - REP_NEUTRAL);
}
@@ -13875,20 +13897,27 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
bool Player::CanResummonPet(uint32 spellid)
{
if (getClass() == CLASS_DEATH_KNIGHT)
switch (getClass())
{
if (CanSeeDKPet())
case CLASS_DEATH_KNIGHT:
if (CanSeeDKPet())
return true;
else if (spellid == 52150) //Raise Dead
return false;
break;
case CLASS_MAGE:
if (HasSpell(31687) && HasAura(70937)) //Has [Summon Water Elemental] spell and [Glyph of Eternal Water].
return true;
break;
case CLASS_HUNTER:
case CLASS_WARLOCK:
return true;
else if (spellid == 52150)
return false;
break;
default:
break;
}
else if (getClass() == CLASS_HUNTER || getClass() == CLASS_MAGE || getClass() == CLASS_WARLOCK)
return true;
if (!HasSpell(spellid))
return false;
return true;
return HasSpell(spellid);
}
bool Player::CanSeeSpellClickOn(Creature const* c) const
@@ -14228,16 +14257,9 @@ void Player::_SaveEntryPoint(CharacterDatabaseTransaction trans)
stmt->SetData (3, m_entryPointData.joinPos.GetPositionZ());
stmt->SetData (4, m_entryPointData.joinPos.GetOrientation());
stmt->SetData(5, m_entryPointData.joinPos.GetMapId());
std::ostringstream ss("");
if (m_entryPointData.HasTaxiPath())
{
for (size_t i = 0; i < m_entryPointData.taxiPath.size(); ++i)
ss << m_entryPointData.taxiPath[i] << ' '; // xinef: segment is stored as last point
}
stmt->SetData(6, ss.str());
stmt->SetData(7, m_entryPointData.mountSpell);
stmt->SetData(6, m_entryPointData.taxiPath[0]);
stmt->SetData(7, m_entryPointData.taxiPath[1]);
stmt->SetData(8, m_entryPointData.mountSpell);
trans->Append(stmt);
}
@@ -15958,3 +15980,10 @@ void Player::ResetSpeakTimers()
m_speakTime = 0;
m_speakCount = 0;
}
std::string Player::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Unit::GetDebugInfo();
return sstr.str();
}
+11 -5
View File
@@ -1035,11 +1035,11 @@ struct EntryPointData
}
uint32 mountSpell{0};
std::vector<uint32> taxiPath;
std::array<uint32, 2> taxiPath;
WorldLocation joinPos;
void ClearTaxiPath() { taxiPath.clear(); }
[[nodiscard]] bool HasTaxiPath() const { return !taxiPath.empty(); }
void ClearTaxiPath() { taxiPath.fill(0); }
[[nodiscard]] bool HasTaxiPath() const { return taxiPath[0] && taxiPath[1]; }
};
class Player : public Unit, public GridObject<Player>
@@ -1126,6 +1126,7 @@ public:
bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 1);
void CleanupAfterTaxiFlight();
void ContinueTaxiFlight();
void SendTaxiNodeStatusMultiple();
// mount_id can be used in scripting calls
[[nodiscard]] bool IsDeveloper() const { return HasPlayerFlag(PLAYER_FLAGS_DEVELOPER); }
@@ -1336,8 +1337,8 @@ public:
bool BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot);
bool _StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore);
float GetReputationPriceDiscount(Creature const* creature) const;
float GetReputationPriceDiscount(FactionTemplateEntry const* vendorFaction) const;
[[nodiscard]] float GetReputationPriceDiscount(Creature const* creature) const;
[[nodiscard]] float GetReputationPriceDiscount(FactionTemplateEntry const* factionTemplate) const;
[[nodiscard]] Player* GetTrader() const { return m_trade ? m_trade->GetTrader() : nullptr; }
[[nodiscard]] TradeData* GetTradeData() const { return m_trade; }
@@ -2429,6 +2430,8 @@ public:
bool CanTeleport() { return m_canTeleport; }
void SetCanTeleport(bool value) { m_canTeleport = value; }
bool CanKnockback() { return m_canKnockback; }
void SetCanKnockback(bool value) { m_canKnockback = value; }
bool isAllowedToLoot(Creature const* creature);
@@ -2557,6 +2560,8 @@ public:
void ResetSpeakTimers();
std::string GetDebugInfo() const override;
protected:
// Gamemaster whisper whitelist
WhisperListContainer WhisperList;
@@ -2884,6 +2889,7 @@ private:
bool m_bMustDelayTeleport;
bool m_bHasDelayedTeleport;
bool m_canTeleport;
bool m_canKnockback;
std::unique_ptr<PetStable> m_petStable;
@@ -4894,21 +4894,9 @@ void Player::_LoadEntryPointData(PreparedQueryResult result)
fields[2].Get<float>(), // Z
fields[3].Get<float>()); // Orientation
std::string_view taxi = fields[5].Get<std::string_view>();
if (!taxi.empty())
{
for (auto const& itr : Acore::Tokenize(taxi, ' ', false))
{
uint32 node = Acore::StringTo<uint32>(itr).value_or(0);
m_entryPointData.taxiPath.emplace_back(node);
}
// Check integrity
if (m_entryPointData.taxiPath.size() < 3)
m_entryPointData.ClearTaxiPath();
}
m_entryPointData.mountSpell = fields[6].Get<uint32>();
m_entryPointData.taxiPath[0] = fields[5].Get<uint32>();
m_entryPointData.taxiPath[1] = fields[6].Get<uint32>();
m_entryPointData.mountSpell = fields[7].Get<uint32>();
}
bool Player::LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid::LowType guid)
@@ -5190,10 +5178,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
// xinef: restore taxi flight from entry point data
if (m_entryPointData.HasTaxiPath())
{
for (size_t i = 0; i < m_entryPointData.taxiPath.size() - 1; ++i)
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[i]);
m_taxi.SetTaxiSegment(m_entryPointData.taxiPath[m_entryPointData.taxiPath.size() - 1]);
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[0]);
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[1]);
m_entryPointData.ClearTaxiPath();
}
}
+48 -17
View File
@@ -20,11 +20,6 @@
#include "Tokenize.h"
#include "StringConvert.h"
PlayerTaxi::PlayerTaxi() : _taxiSegment(0)
{
memset(m_taximask, 0, sizeof(m_taximask));
}
void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level)
{
// class specific initial known nodes
@@ -136,9 +131,25 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, TeamI
{
ClearTaxiDestinations();
for (auto const& itr : Acore::Tokenize(values, ' ', false))
std::vector<std::string_view> tokens = Acore::Tokenize(values, ' ', false);
auto itr = tokens.begin();
if (itr != tokens.end())
{
if (Optional<uint32> node = Acore::StringTo<uint32>(itr))
if (Optional<uint32> faction = Acore::StringTo<uint32>(*itr))
{
m_flightMasterFactionId = *faction;
}
else
{
return false;
}
}
else
return false;
while ((++itr) != tokens.end())
{
if (Optional<uint32> node = Acore::StringTo<uint32>(*itr))
{
AddTaxiDestination(*node);
}
@@ -148,26 +159,33 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, TeamI
}
}
if (m_TaxiDestinations.empty())
{
return true;
}
// Check integrity
if (m_TaxiDestinations.size() < 3)
if (m_TaxiDestinations.size() < 2)
{
return false;
}
// xinef: current segment is saved as last destination in db
_taxiSegment = m_TaxiDestinations[m_TaxiDestinations.size() - 1];
m_TaxiDestinations.pop_back();
for (size_t i = 0; i < m_TaxiDestinations.size() - 1; ++i)
for (size_t i = 1; i < m_TaxiDestinations.size(); ++i)
{
uint32 cost;
uint32 path;
sObjectMgr->GetTaxiPath(m_TaxiDestinations[i], m_TaxiDestinations[i + 1], path, cost);
sObjectMgr->GetTaxiPath(m_TaxiDestinations[i - 1], m_TaxiDestinations[i], path, cost);
if (!path)
{
return false;
}
}
// can't load taxi path without mount set (quest taxi path?)
if (!sObjectMgr->GetTaxiMountDisplayId(GetTaxiSource(), teamId, true))
{
return false;
}
return true;
}
@@ -175,26 +193,34 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, TeamI
std::string PlayerTaxi::SaveTaxiDestinationsToString()
{
if (m_TaxiDestinations.empty())
{
return "";
}
ASSERT(m_TaxiDestinations.size() >= 2);
std::ostringstream ss;
ss << m_flightMasterFactionId << ' ';
for (size_t i = 0; i < m_TaxiDestinations.size(); ++i)
{
ss << m_TaxiDestinations[i] << ' ';
}
ss << _taxiSegment << ' ';
return ss.str();
}
uint32 PlayerTaxi::GetCurrentTaxiPath() const
{
if (m_TaxiDestinations.size() < 2 || m_TaxiDestinations.size() <= _taxiSegment + 1)
if (m_TaxiDestinations.size() < 2)
{
return 0;
}
uint32 path;
uint32 cost;
sObjectMgr->GetTaxiPath(m_TaxiDestinations[_taxiSegment], m_TaxiDestinations[_taxiSegment + 1], path, cost);
sObjectMgr->GetTaxiPath(m_TaxiDestinations[0], m_TaxiDestinations[1], path, cost);
return path;
}
@@ -205,3 +231,8 @@ std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi)
ss << taxi.m_taximask[i] << ' ';
return ss;
}
FactionTemplateEntry const* PlayerTaxi::GetFlightMasterFactionTemplate() const
{
return sFactionTemplateStore.LookupEntry(m_flightMasterFactionId);
}
+11 -12
View File
@@ -26,7 +26,7 @@ class ByteBuffer;
class AC_GAME_API PlayerTaxi
{
public:
PlayerTaxi();
PlayerTaxi() : m_flightMasterFactionId(0) { m_taximask.fill(0); }
~PlayerTaxi() = default;
// Nodes
@@ -59,29 +59,28 @@ public:
bool LoadTaxiDestinationsFromString(std::string const& values, TeamId teamId);
std::string SaveTaxiDestinationsToString();
void ClearTaxiDestinations() { m_TaxiDestinations.clear(); _taxiSegment = 0; }
void ClearTaxiDestinations() { m_TaxiDestinations.clear(); }
void AddTaxiDestination(uint32 dest) { m_TaxiDestinations.push_back(dest); }
[[nodiscard]] uint32 GetTaxiSource() const { return m_TaxiDestinations.size() <= _taxiSegment + 1 ? 0 : m_TaxiDestinations[_taxiSegment]; }
[[nodiscard]] uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() <= _taxiSegment + 1 ? 0 : m_TaxiDestinations[_taxiSegment + 1]; }
[[nodiscard]] uint32 GetTaxiSource() const { return m_TaxiDestinations.empty() ? 0 : m_TaxiDestinations.front(); }
[[nodiscard]] uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() < 2 ? 0 : m_TaxiDestinations[1]; }
[[nodiscard]] uint32 GetCurrentTaxiPath() const;
uint32 NextTaxiDestination()
{
++_taxiSegment;
m_TaxiDestinations.pop_front();
return GetTaxiDestination();
}
// xinef:
void SetTaxiSegment(uint32 segment) { _taxiSegment = segment; }
[[nodiscard]] uint32 GetTaxiSegment() const { return _taxiSegment; }
[[nodiscard]] std::vector<uint32> const& GetPath() const { return m_TaxiDestinations; }
[[nodiscard]] std::deque<uint32> const& GetPath() const { return m_TaxiDestinations; }
[[nodiscard]] bool empty() const { return m_TaxiDestinations.empty(); }
[[nodiscard]] FactionTemplateEntry const* GetFlightMasterFactionTemplate() const;
void SetFlightMasterFactionTemplateId(uint32 factionTemplateId) { m_flightMasterFactionId = factionTemplateId; }
friend std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi);
private:
TaxiMask m_taximask;
std::vector<uint32> m_TaxiDestinations;
uint32 _taxiSegment;
std::deque<uint32> m_TaxiDestinations;
uint32 m_flightMasterFactionId;
};
#endif
+31 -29
View File
@@ -116,38 +116,40 @@ void Totem::UnSummon(uint32 msTime)
CombatStop();
RemoveAurasDueToSpell(GetSpell(), GetGUID());
Unit* owner = GetOwner();
// clear owner's totem slot
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
if (Unit* owner = GetOwner())
{
if (owner->m_SummonSlot[i] == GetGUID())
// clear owner's totem slot
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
{
owner->m_SummonSlot[i].Clear();
break;
}
}
owner->RemoveAurasDueToSpell(GetSpell(), GetGUID());
// Remove Sentry Totem Aura
if (GetEntry() == SENTRY_TOTEM_ENTRY)
owner->RemoveAurasDueToSpell(SENTRY_TOTEM_SPELLID);
//remove aura all party members too
if (Player* player = owner->ToPlayer())
{
player->SendAutoRepeatCancel(this);
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
player->SendCooldownEvent(spell, 0, nullptr, false);
if (Group* group = player->GetGroup())
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (owner->m_SummonSlot[i] == GetGUID())
{
Player* target = itr->GetSource();
if (target && target->IsInMap(player) && group->SameSubGroup(player, target))
target->RemoveAurasDueToSpell(GetSpell(), GetGUID());
owner->m_SummonSlot[i].Clear();
break;
}
}
owner->RemoveAurasDueToSpell(GetSpell(), GetGUID());
// Remove Sentry Totem Aura
if (GetEntry() == SENTRY_TOTEM_ENTRY)
owner->RemoveAurasDueToSpell(SENTRY_TOTEM_SPELLID);
//remove aura all party members too
if (Player* player = owner->ToPlayer())
{
player->SendAutoRepeatCancel(this);
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
player->SendCooldownEvent(spell, 0, nullptr, false);
if (Group* group = player->GetGroup())
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{
Player* target = itr->GetSource();
if (target && target->IsInMap(player) && group->SameSubGroup(player, target))
target->RemoveAurasDueToSpell(GetSpell(), GetGUID());
}
}
}
}
@@ -1004,3 +1004,10 @@ void StaticTransport::RemovePassenger(WorldObject* passenger, bool withAll)
}
}
}
std::string MotionTransport::GetDebugInfo() const
{
std::stringstream sstr;
sstr << GameObject::GetDebugInfo();
return sstr.str();
}
@@ -78,6 +78,7 @@ public:
uint32 GetPeriod() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
void SetPeriod(uint32 period) { SetUInt32Value(GAMEOBJECT_LEVEL, period); }
std::string GetDebugInfo() const override;
private:
void MoveToNextWaypoint();
float CalculateSegmentPos(float perc);
+35 -14
View File
@@ -465,6 +465,7 @@ void Unit::Update(uint32 p_time)
// xinef: if attack time > 0, reduce by diff
// if on next update, attack time < 0 assume player didnt attack - set to 0
bool suspendAttackTimer = false;
bool suspendRangedAttackTimer = false;
if (IsPlayer() && HasUnitState(UNIT_STATE_CASTING))
{
for (Spell* spell : m_currentSpells)
@@ -473,6 +474,11 @@ void Unit::Update(uint32 p_time)
{
if (spell->GetSpellInfo()->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS))
{
if (spell->IsChannelActive())
{
suspendRangedAttackTimer = true;
}
suspendAttackTimer = true;
break;
}
@@ -493,9 +499,12 @@ void Unit::Update(uint32 p_time)
}
}
if (int32 ranged_attack = getAttackTimer(RANGED_ATTACK))
if (!suspendRangedAttackTimer)
{
setAttackTimer(RANGED_ATTACK, ranged_attack > 0 ? ranged_attack - (int32) p_time : 0);
if (int32 ranged_attack = getAttackTimer(RANGED_ATTACK))
{
setAttackTimer(RANGED_ATTACK, ranged_attack > 0 ? ranged_attack - (int32)p_time : 0);
}
}
// update abilities available only for fraction of time
@@ -1109,7 +1118,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
{
Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
ASSERT(he && he->duel);
ASSERT_NODEBUGINFO(he && he->duel);
if (duel_wasMounted) // In this case victim==mount
victim->SetHealth(1);
@@ -2415,7 +2424,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A
DealMeleeDamage(&damageInfo, true);
DamageInfo dmgInfo(damageInfo);
ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage,
Unit::ProcDamageAndSpell(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage,
damageInfo.attackType, nullptr, nullptr, -1, nullptr, &dmgInfo);
if (GetTypeId() == TYPEID_PLAYER)
@@ -5961,15 +5970,15 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo,
SendSpellNonMeleeDamageLog(&log);
}
void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase)
void Unit::ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase)
{
// Not much to do if no flags are set.
if (procAttacker)
ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
if (procAttacker && actor)
actor->ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
// Now go on with a victim's events'n'auras
// Not much to do if no flags are set or there is no victim
if (victim && victim->IsAlive() && procVictim)
victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
victim->ProcDamageAndSpellFor(true, actor, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
}
void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo)
@@ -6151,7 +6160,7 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
}
//victim may be nullptr
bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc /*= nullptr*/)
{
SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
uint32 effIndex = triggeredByAura->GetEffIndex();
@@ -7077,7 +7086,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
case 28719:
{
// mana back
basepoints0 = int32(CalculatePct(procSpell->ManaCost, 30));
basepoints0 = int32(CalculatePct(spellProc->GetPowerCost(), 30));
target = this;
triggered_spell_id = 28742;
break;
@@ -16009,7 +16018,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
case SPELL_AURA_DUMMY:
{
LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} dummy aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown))
if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procSpell))
takeCharges = true;
break;
}
@@ -17406,15 +17415,15 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
if (killer && (killer->IsPet() || killer->IsTotem()))
if (Unit* owner = killer->GetOwner())
{
owner->ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
Unit::ProcDamageAndSpell(owner, victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
sScriptMgr->OnCreatureKilledByPet( killer->GetCharmerOrOwnerPlayerOrPlayerItself(), victim->ToCreature());
}
if (killer != victim && !victim->IsCritter())
killer->ProcDamageAndSpell(victim, killer ? PROC_FLAG_KILL : 0, PROC_FLAG_KILLED, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
Unit::ProcDamageAndSpell(killer, victim, killer ? PROC_FLAG_KILL : 0, PROC_FLAG_KILLED, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
// Proc auras on death - must be before aura/combat remove
victim->ProcDamageAndSpell(nullptr, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
Unit::ProcDamageAndSpell(victim, nullptr, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
// update get killing blow achievements, must be done before setDeathState to be able to require auras on target
// and before Spirit of Redemption as it also removes auras
@@ -18750,6 +18759,7 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
player->SetCanFly(true, true);
sScriptMgr->AnticheatSetSkipOnePacketForASH(player, true);
player->SetCanKnockback(true);
}
}
@@ -20843,3 +20853,14 @@ bool Unit::IsInDisallowedMountForm() const
return false;
}
std::string Unit::GetDebugInfo() const
{
std::stringstream sstr;
sstr << WorldObject::GetDebugInfo() << "\n"
<< std::boolalpha
<< "AliveState: " << IsAlive()
<< " UnitMovementFlags: " << GetUnitMovementFlags() << " ExtraUnitMovementFlags: " << GetExtraUnitMovementFlags()
<< " Class: " << std::to_string(getClass());
return sstr.str();
}
+4 -2
View File
@@ -1525,7 +1525,7 @@ public:
static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr);
static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth);
void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
static void ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
void GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTriggeringProc, std::list<AuraApplication*>* procAuras, ProcEventInfo eventInfo);
@@ -2431,6 +2431,8 @@ public:
virtual bool SetCannotReachTarget(bool cannotReach, bool isChase = true);
[[nodiscard]] bool CanNotReachTarget() const { return m_cannotReachTarget; }
std::string GetDebugInfo() const override;
protected:
explicit Unit (bool isWorldObject);
@@ -2515,7 +2517,7 @@ protected:
private:
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc = nullptr);
bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled);
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo);
bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown);
+2 -2
View File
@@ -9875,8 +9875,8 @@ void ObjectMgr::SendServerMail(Player* player, uint32 id, uint32 reqLevel, uint3
MailSender sender(MAIL_NORMAL, player->GetGUID().GetCounter(), MAIL_STATIONERY_GM);
MailDraft draft(subject, body);
draft.AddMoney(player->GetTeamId() == TEAM_ALLIANCE ? rewardMoneyH : rewardMoneyA);
if (Item* mailItem = Item::CreateItem(player->GetTeamId() == TEAM_ALLIANCE ? rewardItemH : rewardItemA, player->GetTeamId() == TEAM_ALLIANCE ? rewardItemCountH : rewardItemCountA))
draft.AddMoney(player->GetTeamId() == TEAM_ALLIANCE ? rewardMoneyA : rewardMoneyH);
if (Item* mailItem = Item::CreateItem(player->GetTeamId() == TEAM_ALLIANCE ? rewardItemA : rewardItemH, player->GetTeamId() == TEAM_ALLIANCE ? rewardItemCountA : rewardItemCountH))
{
mailItem->SaveToDB(trans);
draft.AddItem(mailItem);
+4 -2
View File
@@ -1449,7 +1449,8 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
roll->getLoot()->unlootedCount--;
AllowedLooterSet looters = item->GetAllowedLooters();
Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters);
sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), NEED, roll);
if (_item)
sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), NEED, roll);
player->UpdateLootAchievements(item, roll->getLoot());
}
else
@@ -1518,7 +1519,8 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
roll->getLoot()->unlootedCount--;
AllowedLooterSet looters = item->GetAllowedLooters();
Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters);
sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), GREED, roll);
if (_item)
sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), GREED, roll);
player->UpdateLootAchievements(item, roll->getLoot());
}
else
@@ -506,6 +506,7 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData)
sAuctionMgr->SendAuctionSalePendingMail(auction, trans);
sAuctionMgr->SendAuctionSuccessfulMail(auction, trans);
sAuctionMgr->SendAuctionWonMail(auction, trans);
sScriptMgr->OnAuctionSuccessful(auctionHouse, auction);
SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, ERR_AUCTION_OK);
@@ -533,13 +533,20 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
}
else // leave queue
{
bgQueue.RemovePlayer(_player->GetGUID(), true);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
for (auto const& playerGuid : ginfo.Players)
{
auto player = ObjectAccessor::FindConnectedPlayer(playerGuid);
if (!player)
continue;
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
SendPacket(&data);
bgQueue.RemovePlayer(playerGuid, true);
player->RemoveBattlegroundQueueId(bgQueueTypeId);
LOG_DEBUG("bg.battleground", "Battleground: player {} {} left queue for bgtype {}, queue type {}.", _player->GetName(), _player->GetGUID().ToString(), bg->GetBgTypeID(), bgQueueTypeId);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
player->SendDirectMessage(&data);
LOG_DEBUG("bg.battleground", "Battleground: player {} {} left queue for bgtype {}, queue type {}.", player->GetName(), playerGuid.ToString(), bg->GetBgTypeID(), bgQueueTypeId);
}
// player left queue, we should update it - do not update Arena Queue
if (!ginfo.ArenaType)
@@ -2189,7 +2189,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact
// Update Taxi path
TaxiMask newTaxiMask;
memset(newTaxiMask, 0, sizeof(newTaxiMask));
newTaxiMask.fill(0);
TaxiMask const& factionMask = newTeam == TEAM_HORDE ? sHordeTaxiNodesMask : sAllianceTaxiNodesMask;
for (auto const& itr : sTaxiPathSetBySource)
@@ -2535,6 +2535,12 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact
}
}
// Re-check all achievement criterias
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
stmt->SetData(0, uint16(AT_LOGIN_CHECK_ACHIEVS));
stmt->SetData(1, lowGuid);
trans->Append(stmt);
CharacterDatabase.CommitTransaction(trans);
LOG_DEBUG("entities.player", "{} (IP: {}) changed race from {} to {}", GetPlayerInfo(), GetRemoteAddress(), oldRace, factionChangeInfo->Race);
@@ -188,6 +188,22 @@ void WorldSession::HandleMoveWorldportAck()
GetPlayer()->SendInitialPacketsAfterAddToMap();
// flight fast teleport case
if (GetPlayer()->IsInFlight())
{
if (!GetPlayer()->InBattleground())
{
// short preparations to continue flight
MovementGenerator* movementGenerator = GetPlayer()->GetMotionMaster()->top();
movementGenerator->Initialize(GetPlayer());
return;
}
// battleground state prepare, stop flight
GetPlayer()->GetMotionMaster()->MovementExpired();
GetPlayer()->CleanupAfterTaxiFlight();
}
// resurrect character at enter into instance where his corpse exist after add to map
Corpse* corpse = GetPlayer()->GetMap()->GetCorpseByPlayer(GetPlayer()->GetGUID());
if (corpse && corpse->GetType() != CORPSE_BONES)
+53 -11
View File
@@ -15,6 +15,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GameTime.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Player.h"
@@ -36,25 +37,24 @@ void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvData)
void WorldSession::SendTaxiStatus(ObjectGuid guid)
{
// cheating checks
Creature* unit = GetPlayer()->GetMap()->GetCreature(guid);
if (!unit)
Player* const player = GetPlayer();
Creature* unit = ObjectAccessor::GetCreature(*player, guid);
if (!unit || unit->IsHostileTo(player) || !unit->HasNpcFlag(UNIT_NPC_FLAG_FLIGHTMASTER))
{
LOG_DEBUG("network", "WorldSession::SendTaxiStatus - Unit ({}) not found.", guid.ToString());
return;
}
uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeamId());
// not found nearest
if (curloc == 0)
// find taxi node
uint32 nearest = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), player->GetTeamId());
if (!nearest)
{
return;
LOG_DEBUG("network", "WORLD: current location {} ", curloc);
}
WorldPacket data(SMSG_TAXINODE_STATUS, 9);
data << guid;
data << uint8(GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) ? 1 : 0);
data << uint8(player->m_taxi.IsTaximaskNodeKnown(nearest) ? 1 : 0);
SendPacket(&data);
LOG_DEBUG("network", "WORLD: Sent SMSG_TAXINODE_STATUS");
}
@@ -166,7 +166,7 @@ void WorldSession::SendDiscoverNewTaxiNode(uint32 nodeid)
}
}
void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket& recvData)
void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recvData)
{
LOG_DEBUG("network", "WORLD: Received CMSG_ACTIVATETAXIEXPRESS");
@@ -179,6 +179,7 @@ void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket& recvData)
if (!npc)
{
LOG_DEBUG("network", "WORLD: HandleActivateTaxiExpressOpcode - Unit ({}) not found or you can't interact with it.", guid.ToString());
SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
return;
}
std::vector<uint32> nodes;
@@ -218,6 +219,46 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData)
ReadMovementInfo(recvData, &movementInfo);
recvData.read_skip<uint32>(); // spline id
// in taxi flight packet received in 2 case:
// 1) end taxi path in far (multi-node) flight
// 2) switch from one map to other in case multim-map taxi path
// we need process only (1)
uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination();
if (curDest)
{
TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest);
// far teleport case
if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
{
if (FlightPathMovementGenerator* flight = dynamic_cast<FlightPathMovementGenerator*>(GetPlayer()->GetMotionMaster()->top()))
{
// short preparations to continue flight
flight->SetCurrentNodeAfterTeleport();
TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()];
flight->SkipCurrentNode();
GetPlayer()->TeleportTo(curDestNode->map_id, node->x, node->y, node->z, GetPlayer()->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI);
}
}
return;
}
// at this point only 1 node is expected (final destination)
if (GetPlayer()->m_taxi.GetPath().size() != 1)
{
return;
}
GetPlayer()->CleanupAfterTaxiFlight();
GetPlayer()->SetFallInformation(GameTime::GetGameTime().count(), GetPlayer()->GetPositionZ());
if (GetPlayer()->pvpInfo.IsHostile)
{
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
}
}
void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recvData)
@@ -234,6 +275,7 @@ void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recvData)
if (!npc)
{
LOG_DEBUG("network", "WORLD: HandleActivateTaxiOpcode - Unit ({}) not found or you can't interact with it.", guid.ToString());
SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
return;
}
@@ -94,7 +94,7 @@ InstanceSave* InstanceSaveMgr::AddInstanceSave(uint32 mapId, uint32 instanceId,
}
else
{
resetTime = GameTime::GetGameTime().count() + 3 * DAY; // normals expire after 3 days even if someone is still bound to them, cleared on startup
resetTime = GameTime::GetGameTime().count() + static_cast<long long>(3) * DAY; // normals expire after 3 days even if someone is still bound to them, cleared on startup
extendedResetTime = 0;
}
InstanceSave* save = new InstanceSave(mapId, instanceId, difficulty, resetTime, extendedResetTime);
-8
View File
@@ -429,14 +429,6 @@ bool LootItem::AllowedForPlayer(Player const* player, bool isGivenByMasterLooter
return false;
}
// Checking for unique or unique(XX) objects
// master looter should still be able to see the loot to give to people.
// casting to avoid warnings, it's unlikely there's an item with unique but 2^31 items allowed.
if (!isMasterLooter && pProto->MaxCount > 0 && ((int32)player->GetItemCount(itemid, true) >= pProto->MaxCount))
{
return false;
}
// not show loot for not own team
if ((pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && player->GetTeamId(true) != TEAM_HORDE)
{
+18
View File
@@ -4027,3 +4027,21 @@ void Map::DeleteCorpseData()
stmt->SetData(1, GetInstanceId());
CharacterDatabase.Execute(stmt);
}
std::string Map::GetDebugInfo() const
{
std::stringstream sstr;
sstr << std::boolalpha
<< "Id: " << GetId() << " InstanceId: " << GetInstanceId() << " Difficulty: " << std::to_string(GetDifficulty())
<< " HasPlayers: " << HavePlayers();
return sstr.str();
}
std::string InstanceMap::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Map::GetDebugInfo() << "\n"
<< std::boolalpha
<< "ScriptId: " << GetScriptId() << " ScriptName: " << GetScriptName();
return sstr.str();
}
+5
View File
@@ -649,6 +649,8 @@ public:
return m_activeNonPlayers.size();
}
virtual std::string GetDebugInfo() const;
private:
void LoadMapAndVMap(int gx, int gy);
void LoadVMap(int gx, int gy);
@@ -830,6 +832,9 @@ public:
[[nodiscard]] uint32 GetMaxResetDelay() const;
void InitVisibilityDistance() override;
std::string GetDebugInfo() const override;
private:
bool m_resetAfterUnload;
bool m_unloadWhenEmpty;
@@ -270,35 +270,69 @@ void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature)
uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
{
if (i_currentNode >= i_path.size())
{
return i_path.size();
}
uint32 curMapId = i_path[i_currentNode]->mapid;
for (uint32 i = i_currentNode; i < i_path.size(); ++i)
{
if (i_path[i]->mapid != curMapId)
{
return i;
}
}
return i_path.size();
}
#define SKIP_SPLINE_POINT_DISTANCE_SQ (40.0f * 40.0f)
bool IsNodeIncludedInShortenedPath(TaxiPathNodeEntry const* p1, TaxiPathNodeEntry const* p2)
{
return p1->mapid != p2->mapid || std::pow(p1->x - p2->x, 2) + std::pow(p1->y - p2->y, 2) > SKIP_SPLINE_POINT_DISTANCE_SQ;
}
void FlightPathMovementGenerator::LoadPath(Player* player)
{
_pointsForPathSwitch.clear();
std::vector<uint32> const& taxi = player->m_taxi.GetPath();
for (uint32 src = player->m_taxi.GetTaxiSegment(), dst = player->m_taxi.GetTaxiSegment() + 1; dst < taxi.size(); src = dst++)
std::deque<uint32> const& taxi = player->m_taxi.GetPath();
float discount = player->GetReputationPriceDiscount(player->m_taxi.GetFlightMasterFactionTemplate());
for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++)
{
uint32 path, cost;
sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost);
if (path > sTaxiPathNodesByPath.size())
{
return;
}
TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path];
if (!nodes.empty())
{
TaxiPathNodeEntry const* start = nodes[0];
TaxiPathNodeEntry const* end = nodes[nodes.size() - 1];
bool passedPreviousSegmentProximityCheck = false;
for (uint32 i = 0; i < nodes.size(); ++i)
i_path.push_back(nodes[i]);
{
if (passedPreviousSegmentProximityCheck || !src || i_path.empty() || IsNodeIncludedInShortenedPath(i_path[i_path.size() - 1], nodes[i]))
{
if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) &&
(dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.size() - 1)))
{
passedPreviousSegmentProximityCheck = true;
i_path.push_back(nodes[i]);
}
}
else
{
i_path.pop_back();
--_pointsForPathSwitch.back().PathIndex;
}
}
}
_pointsForPathSwitch.push_back(uint32(i_path.size() - 1));
_pointsForPathSwitch.push_back({ uint32(i_path.size() - 1), int32(ceil(cost * discount)) });
}
}
@@ -313,7 +347,7 @@ void FlightPathMovementGenerator::DoFinalize(Player* player)
// remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack)
player->ClearUnitState(UNIT_STATE_IN_FLIGHT);
// xinef: this should be cleaned by CleanupAfterTaxiFlight(); function!
player->m_taxi.ClearTaxiDestinations();
player->Dismount();
player->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
@@ -324,6 +358,8 @@ void FlightPathMovementGenerator::DoFinalize(Player* player)
// this prevent cheating with landing point at lags
// when client side flight end early in comparison server side
player->StopMoving();
// When the player reaches the last flight point, teleport to destination taxi node location
player->SetFallInformation(GameTime::GetGameTime().count(), player->GetPositionZ());
}
@@ -334,13 +370,23 @@ void FlightPathMovementGenerator::DoFinalize(Player* player)
void FlightPathMovementGenerator::DoReset(Player* player)
{
uint32 end = GetPathAtMapEnd();
uint32 currentNodeId = GetCurrentNode();
if (currentNodeId == end)
{
LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::DoReset: trying to start a flypath from the end point. {}", player->GetGUID().ToString().c_str());
return;
}
player->getHostileRefMgr().setOnlineOfflineState(false);
player->AddUnitState(UNIT_STATE_IN_FLIGHT);
player->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
Movement::MoveSplineInit init(player);
uint32 end = GetPathAtMapEnd();
for (uint32 i = GetCurrentNode(); i < end; ++i)
// Providing a starting vertex since the taxi paths do not provide such
init.Path().push_back(G3D::Vector3(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()));
for (uint32 i = currentNodeId; i != end; ++i)
{
G3D::Vector3 vertice(i_path[i]->x, i_path[i]->y, i_path[i]->z);
init.Path().push_back(vertice);
@@ -353,77 +399,40 @@ void FlightPathMovementGenerator::DoReset(Player* player)
bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
{
if (!player)
return false;
// xinef: map was switched
if (_mapSwitch)
{
DoInitialize(player);
_mapSwitch = false;
return true;
}
uint32 pointId = (uint32)player->movespline->currentPathIdx();
if (pointId > i_currentNode)
// skipping the first spline path point because it's our starting point and not a taxi path point
uint32 pointId = player->movespline->currentPathIdx() <= 0 ? 0 : player->movespline->currentPathIdx() - 1;
if (pointId > i_currentNode && i_currentNode < i_path.size() - 1)
{
bool departureEvent = true;
do
{
if (i_currentNode >= i_path.size())
{
LOG_INFO("misc", "TAXI NODE WAS GREATER THAN PATH SIZE, {}, POINTID: {}, NODESIZE: {}, CURRENT: {}",
player->GetGUID().ToString(), pointId, i_path.size(), i_currentNode);
player->CleanupAfterTaxiFlight();
return false;
}
if (i_path[i_currentNode]->mapid != player->GetMapId())
{
LOG_INFO("misc", "Player on different map, curmap: {}, pointmap: {}, nodesize: {}, currentnode: {}", player->GetMapId(), i_path[i_currentNode]->mapid, i_path.size(), i_currentNode);
player->CleanupAfterTaxiFlight();
return false;
}
ASSERT(i_currentNode < i_path.size(), "Point Id: {}\n{}", pointId, player->GetGUID().ToString().c_str());
DoEventIfAny(player, i_path[i_currentNode], departureEvent);
// xinef: erase any previous points
uint32 curSize = _pointsForPathSwitch.size();
while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front() <= i_currentNode)
while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front().PathIndex <= i_currentNode)
{
_pointsForPathSwitch.pop_front();
// xinef: switch destination only once
if (curSize != _pointsForPathSwitch.size())
player->m_taxi.NextTaxiDestination();
if (!_pointsForPathSwitch.empty())
{
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, _pointsForPathSwitch.front().Cost);
player->ModifyMoney(-_pointsForPathSwitch.front().Cost);
}
}
if (pointId == i_currentNode)
{
break;
}
if (i_currentNode == _preloadTargetNode && player->GetMapId() == _endMapId)
if (i_currentNode == _preloadTargetNode)
{
PreloadEndGrid();
i_currentNode += (uint32)departureEvent;
}
i_currentNode += departureEvent ? 1 : 0;
departureEvent = !departureEvent;
// xinef: map should be switched, do not rely on client packets QQ
if (i_currentNode + 1 < i_path.size() && i_path[i_currentNode + 1]->mapid != player->GetMapId())
{
++i_currentNode;
_mapSwitch = true;
player->TeleportTo(i_path[i_currentNode]->mapid, i_path[i_currentNode]->x, i_path[i_currentNode]->y, i_path[i_currentNode]->z, player->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI);
return true;
}
// xinef: reached the end
if (i_currentNode >= i_path.size() - 1)
{
player->CleanupAfterTaxiFlight();
player->SetFallInformation(GameTime::GetGameTime().count(), player->GetPositionZ());
if (player->pvpInfo.IsHostile)
player->CastSpell(player, 2479, true);
return false;
}
} while (true);
} while (i_currentNode < i_path.size() - 1);
}
return i_currentNode < (i_path.size() - 1);
@@ -432,7 +441,9 @@ bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
{
if (i_path.empty() || i_currentNode >= i_path.size())
{
return;
}
uint32 map0 = i_path[i_currentNode]->mapid;
for (size_t i = i_currentNode + 1; i < i_path.size(); ++i)
@@ -449,11 +460,20 @@ void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry
{
if (uint32 eventid = departure ? node->departureEventID : node->arrivalEventID)
{
LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName());
LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName().c_str());
player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
}
}
bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z)
{
TaxiPathNodeEntry const* node = i_path[i_currentNode];
x = node->x;
y = node->y;
z = node->z;
return true;
}
void FlightPathMovementGenerator::InitEndGridInfo()
{
/*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
@@ -485,11 +505,11 @@ void FlightPathMovementGenerator::PreloadEndGrid()
// Load the grid
if (endMap)
{
LOG_DEBUG("movement", "Preloading rid ({}, {}) for map {} at node index {}/{}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path.size() - 1));
LOG_DEBUG("misc", "Preloading grid ({}, {}) for map %u at node index {}/{}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path.size() - 1));
endMap->LoadGrid(_endGridX, _endGridY);
}
else
{
LOG_DEBUG("movement", "Unable to determine map to preload flightmaster grid");
LOG_DEBUG("misc", "Unable to determine map to preload flightmaster grid");
}
}
@@ -101,40 +101,48 @@ private:
class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, FlightPathMovementGenerator >,
public PathMovementBase<Player, TaxiPathNodeList>
{
public:
explicit FlightPathMovementGenerator(uint32 startNode = 0)
{
i_currentNode = startNode;
_endGridX = 0.0f;
_endGridY = 0.0f;
_endMapId = 0;
_preloadTargetNode = 0;
_mapSwitch = false;
}
void LoadPath(Player* player);
void DoInitialize(Player*);
void DoReset(Player*);
void DoFinalize(Player*);
bool DoUpdate(Player*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
public:
explicit FlightPathMovementGenerator(uint32 startNode = 0)
{
i_currentNode = startNode;
_endGridX = 0.0f;
_endGridY = 0.0f;
_endMapId = 0;
_preloadTargetNode = 0;
}
void LoadPath(Player* player);
void DoInitialize(Player*);
void DoReset(Player*);
void DoFinalize(Player*);
bool DoUpdate(Player*, uint32);
MovementGeneratorType GetMovementGeneratorType() override { return FLIGHT_MOTION_TYPE; }
TaxiPathNodeList const& GetPath() { return i_path; }
uint32 GetPathAtMapEnd() const;
bool HasArrived() const { return (i_currentNode >= i_path.size()); }
void SetCurrentNodeAfterTeleport();
void SkipCurrentNode() { ++i_currentNode; }
void DoEventIfAny(Player* player, TaxiPathNodeEntry const* node, bool departure);
TaxiPathNodeList const& GetPath() { return i_path; }
uint32 GetPathAtMapEnd() const;
bool HasArrived() const { return (i_currentNode >= i_path.size()); }
void SetCurrentNodeAfterTeleport();
void SkipCurrentNode() { ++i_currentNode; }
void DoEventIfAny(Player* player, TaxiPathNodeEntry const* node, bool departure);
void InitEndGridInfo();
void PreloadEndGrid();
bool GetResetPos(Player*, float& x, float& y, float& z);
private:
float _endGridX; //! X coord of last node location
float _endGridY; //! Y coord of last node location
uint32 _endMapId; //! map Id of last node location
uint32 _preloadTargetNode; //! node index where preloading starts
bool _mapSwitch;
void InitEndGridInfo();
void PreloadEndGrid();
std::deque<uint32> _pointsForPathSwitch; //! node indexes and costs where TaxiPath changes
private:
float _endGridX; //! X coord of last node location
float _endGridY; //! Y coord of last node location
uint32 _endMapId; //! map Id of last node location
uint32 _preloadTargetNode; //! node index where preloading starts
struct TaxiNodeChangeInfo
{
uint32 PathIndex;
int32 Cost;
};
std::deque<TaxiNodeChangeInfo> _pointsForPathSwitch; //! node indexes and costs where TaxiPath changes
};
#endif
@@ -1913,6 +1913,10 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
case FORM_FLIGHT:
case FORM_MOONKIN:
{
if (Player* player = target->ToPlayer())
{
player->SetCanTeleport(true);
}
// remove movement affects
target->RemoveAurasByShapeShift();
@@ -6396,8 +6400,8 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
target->SendPeriodicAuraLog(&pInfo);
Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
// allow null caster to call this function
caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
}
void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const
@@ -6485,8 +6489,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
int32 new_damage;
new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false);
// allow null caster to call this function
caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
if (!caster || !caster->IsAlive())
return;
@@ -6668,8 +6672,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
// ignore item heals
if (!haveCastItem && GetAuraType() != SPELL_AURA_OBS_MOD_HEALTH) // xinef: dont allow obs_mod_health to proc spells, this is passive regeneration and not hot
// xinef: allow null caster to proc
caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, heal, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, nullptr, &healInfo);
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, heal, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const
@@ -6857,7 +6860,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
caster->DealSpellDamage(&damageInfo, true);
DamageInfo dmgInfo(damageInfo, DOT);
caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex(), nullptr, &dmgInfo);
Unit::ProcDamageAndSpell(caster, damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex(), nullptr, &dmgInfo);
}
void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
+24 -15
View File
@@ -297,8 +297,8 @@ void AuraApplication::ClientUpdate(bool remove)
uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleEffectMask, WorldObject* owner)
{
ASSERT(spellProto);
ASSERT(owner);
ASSERT_NODEBUGINFO(spellProto);
ASSERT_NODEBUGINFO(owner);
uint8 effMask = 0;
switch (owner->GetTypeId())
{
@@ -325,10 +325,10 @@ uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleE
Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= nullptr*/, bool periodicReset /*= false*/)
{
ASSERT(spellproto);
ASSERT(owner);
ASSERT(caster || casterGUID);
ASSERT(tryEffMask <= MAX_EFFECT_MASK);
ASSERT_NODEBUGINFO(spellproto);
ASSERT_NODEBUGINFO(owner);
ASSERT_NODEBUGINFO(caster || casterGUID);
ASSERT_NODEBUGINFO(tryEffMask <= MAX_EFFECT_MASK);
if (refresh)
*refresh = false;
uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner);
@@ -351,10 +351,10 @@ Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMas
Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, ObjectGuid itemGUID /*= ObjectGuid::Empty*/)
{
ASSERT(spellproto);
ASSERT(owner);
ASSERT(caster || casterGUID);
ASSERT(tryEffMask <= MAX_EFFECT_MASK);
ASSERT_NODEBUGINFO(spellproto);
ASSERT_NODEBUGINFO(owner);
ASSERT_NODEBUGINFO(caster || casterGUID);
ASSERT_NODEBUGINFO(tryEffMask <= MAX_EFFECT_MASK);
uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner);
if (!effMask)
return nullptr;
@@ -363,11 +363,11 @@ Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject
Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid itemGUID /*= ObjectGuid::Empty*/)
{
ASSERT(effMask);
ASSERT(spellproto);
ASSERT(owner);
ASSERT(caster || casterGUID);
ASSERT(effMask <= MAX_EFFECT_MASK);
ASSERT_NODEBUGINFO(effMask);
ASSERT_NODEBUGINFO(spellproto);
ASSERT_NODEBUGINFO(owner);
ASSERT_NODEBUGINFO(caster || casterGUID);
ASSERT_NODEBUGINFO(effMask <= MAX_EFFECT_MASK);
// try to get caster of aura
if (casterGUID)
{
@@ -2707,6 +2707,15 @@ void Aura::SetTriggeredByAuraSpellInfo(SpellInfo const* triggeredByAuraSpellInfo
m_triggeredByAuraSpellInfo = triggeredByAuraSpellInfo;
}
std::string Aura::GetDebugInfo() const
{
std::stringstream sstr;
sstr << std::boolalpha
<< "Id: " << GetId() << " Caster: " << GetCasterGUID().ToString()
<< "\nOwner: " << (GetOwner() ? GetOwner()->GetDebugInfo() : "NULL");
return sstr.str();
}
SpellInfo const* Aura::GetTriggeredByAuraSpellInfo() const
{
return m_triggeredByAuraSpellInfo;
@@ -236,6 +236,8 @@ public:
std::list<AuraScript*> m_loadedScripts;
virtual std::string GetDebugInfo() const;
void SetTriggeredByAuraSpellInfo(SpellInfo const* triggeredByAuraSpellInfo);
SpellInfo const* GetTriggeredByAuraSpellInfo() const;
+15 -6
View File
@@ -2792,7 +2792,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger)
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, &healInfo);
}
// Do damage and triggers
@@ -2871,7 +2871,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (canEffectTrigger)
{
DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE);
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, &dmgInfo);
if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 &&
@@ -2891,7 +2891,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (canEffectTrigger)
{
DamageInfo dmgInfo(damageInfo, NODAMAGE);
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, &dmgInfo);
// Xinef: eg. rogue poisons can proc off cheap shot, etc. so this block should be here also
@@ -3972,7 +3972,7 @@ void Spell::_cast(bool skipCheck)
break;
}
m_originalCaster->ProcDamageAndSpell(m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_CAST);
}
@@ -4312,7 +4312,7 @@ void Spell::_handle_finish_phase()
break;
}
m_originalCaster->ProcDamageAndSpell(m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_FINISH);
}
}
@@ -8155,7 +8155,7 @@ bool ReflectEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
Unit* target = ObjectAccessor::GetUnit(*_caster, _targetGUID);
if (target && _caster->IsInMap(target))
_caster->ProcDamageAndSpell(target, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, _spellInfo);
Unit::ProcDamageAndSpell(_caster, target, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, _spellInfo);
return true;
}
@@ -8866,6 +8866,15 @@ void TriggeredByAuraSpellData::Init(AuraEffect const* aurEff)
tickNumber = aurEff->GetTickNumber();
}
std::string Spell::GetDebugInfo() const
{
std::stringstream sstr;
sstr << std::boolalpha
<< "Id: " << GetSpellInfo()->Id << " OriginalCaster: " << m_originalCasterGUID.ToString()
<< " State: " << getState();
return sstr.str();
}
namespace Acore
{
+2
View File
@@ -606,6 +606,8 @@ public:
Spell** m_selfContainer; // pointer to our spell container (if applicable)
std::string GetDebugInfo() const;
//Spell data
SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example)
WeaponAttackType m_attackType; // For weapon based attack
@@ -4329,6 +4329,25 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(0x00000003, 0x00001000);
});
// Elemental Vulnerability
ApplySpellFix({ 28772 }, [](SpellInfo* spellInfo)
{
spellInfo->Speed = 1;
});
// Find the Ancient Hero: Kill Credit
ApplySpellFix({ 25729 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].TargetA = TARGET_UNIT_SUMMONER;
});
// Artorius Demonic Doom
ApplySpellFix({ 23298 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx4 |= SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS;
spellInfo->AttributesEx6 |= SPELL_ATTR6_IGNORE_CASTER_DAMAGE_MODIFIERS;
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];