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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user