Merge branch 'master' into Playerbot
# Conflicts: # src/server/game/Guilds/Guild.cpp
This commit is contained in:
@@ -64,14 +64,14 @@ void SummonList::DespawnEntry(uint32 entry)
|
||||
}
|
||||
}
|
||||
|
||||
void SummonList::DespawnAll()
|
||||
void SummonList::DespawnAll(uint32 delay /*= 0*/)
|
||||
{
|
||||
while (!storage_.empty())
|
||||
{
|
||||
Creature* summon = ObjectAccessor::GetCreature(*me, storage_.front());
|
||||
storage_.pop_front();
|
||||
if (summon)
|
||||
summon->DespawnOrUnsummon();
|
||||
summon->DespawnOrUnsummon(delay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,11 +384,35 @@ SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mec
|
||||
return apSpell[urand(0, spellCount - 1)];
|
||||
}
|
||||
|
||||
void ScriptedAI::DoResetThreat()
|
||||
void ScriptedAI::DoAddThreat(Unit* unit, float amount)
|
||||
{
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
me->GetThreatMgr().AddThreat(unit, amount);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoModifyThreatByPercent(Unit* unit, int32 pct)
|
||||
{
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
me->GetThreatMgr().ModifyThreatByPercent(unit, pct);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoResetThreat(Unit* unit)
|
||||
{
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
me->GetThreatMgr().ResetThreat(unit);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoResetThreatList()
|
||||
{
|
||||
if (!me->CanHaveThreatList() || me->GetThreatMgr().isThreatListEmpty())
|
||||
{
|
||||
LOG_ERROR("entities.unit.ai", "DoResetThreat called for creature that either cannot have threat list or has empty threat list (me entry = {})", me->GetEntry());
|
||||
LOG_ERROR("entities.unit.ai", "DoResetThreatList called for creature that either cannot have threat list or has empty threat list (me entry = {})", me->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -399,14 +423,8 @@ float ScriptedAI::DoGetThreat(Unit* unit)
|
||||
{
|
||||
if (!unit)
|
||||
return 0.0f;
|
||||
return me->GetThreatMgr().GetThreat(unit);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoModifyThreatPercent(Unit* unit, int32 pct)
|
||||
{
|
||||
if (!unit)
|
||||
return;
|
||||
me->GetThreatMgr().ModifyThreatByPercent(unit, pct);
|
||||
return me->GetThreatMgr().GetThreat(unit);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoTeleportPlayer(Unit* unit, float x, float y, float z, float o)
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
void Summon(Creature const* summon) { storage_.push_back(summon->GetGUID()); }
|
||||
void Despawn(Creature const* summon) { storage_.remove(summon->GetGUID()); }
|
||||
void DespawnEntry(uint32 entry);
|
||||
void DespawnAll();
|
||||
void DespawnAll(uint32 delay = 0);
|
||||
bool IsAnyCreatureAlive() const;
|
||||
bool IsAnyCreatureWithEntryAlive(uint32 entry) const;
|
||||
bool IsAnyCreatureInCombat() const;
|
||||
@@ -304,11 +304,20 @@ struct ScriptedAI : public CreatureAI
|
||||
//Plays music for all players in the zone (zone = true) or the area (zone = false)
|
||||
void DoPlayMusic(uint32 soundId, bool zone);
|
||||
|
||||
//Drops all threat to 0%. Does not remove players from the threat list
|
||||
void DoResetThreat();
|
||||
// Add specified amount of threat directly to victim (ignores redirection effects) - also puts victim in combat and engages them if necessary
|
||||
void DoAddThreat(Unit* unit, float amount);
|
||||
|
||||
// Adds/removes the specified percentage from the specified victim's threat (to who, or me if not specified)
|
||||
void DoModifyThreatByPercent(Unit* unit, int32 pct);
|
||||
|
||||
//Drops all threat to 0%. Does not remove players from the threat list
|
||||
void DoResetThreat(Unit* unit);
|
||||
|
||||
// Resets the specified unit's threat list (me if not specified) - does not delete entries, just sets their threat to zero
|
||||
void DoResetThreatList();
|
||||
|
||||
// Returns the threat level of victim towards who (or me if not specified)
|
||||
float DoGetThreat(Unit* unit);
|
||||
void DoModifyThreatPercent(Unit* unit, int32 pct);
|
||||
|
||||
//Teleports a player without dropping threat (only teleports to same map)
|
||||
void DoTeleportPlayer(Unit* unit, float x, float y, float z, float o);
|
||||
|
||||
@@ -40,6 +40,12 @@ BattlefieldMgr* BattlefieldMgr::instance()
|
||||
|
||||
void BattlefieldMgr::InitBattlefield()
|
||||
{
|
||||
if (sWorld->getIntConfig(CONFIG_WINTERGRASP_ENABLE) == 2)
|
||||
{
|
||||
LOG_INFO("server.loading", "Battlefield: Wintergrasp is disabled.");
|
||||
LOG_INFO("server.loading", " ");
|
||||
return;
|
||||
}
|
||||
Battlefield* pBf = new BattlefieldWG;
|
||||
// respawn, init variables
|
||||
if (!pBf->SetupBattlefield())
|
||||
|
||||
@@ -50,7 +50,7 @@ bool BattlefieldWG::SetupBattlefield()
|
||||
InitStalker(BATTLEFIELD_WG_NPC_STALKER, WintergraspStalkerPos[0], WintergraspStalkerPos[1], WintergraspStalkerPos[2], WintergraspStalkerPos[3]);
|
||||
|
||||
m_MaxPlayer = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MAX);
|
||||
m_IsEnabled = sWorld->getBoolConfig(CONFIG_WINTERGRASP_ENABLE);
|
||||
m_IsEnabled = sWorld->getIntConfig(CONFIG_WINTERGRASP_ENABLE) == 1;
|
||||
m_MinPlayer = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MIN);
|
||||
m_MinLevel = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MIN_LVL);
|
||||
m_BattleTime = sWorld->getIntConfig(CONFIG_WINTERGRASP_BATTLETIME) * MINUTE * IN_MILLISECONDS;
|
||||
|
||||
@@ -729,8 +729,8 @@ void BattlegroundAV::ChangeMineOwner(uint8 mine, TeamId teamId, bool initial)
|
||||
{
|
||||
m_Mine_Reclaim_Timer[mine] = AV_MINE_RECLAIM_TIMER;
|
||||
char buf[256];
|
||||
sprintf(buf, GetAcoreString(LANG_BG_AV_MINE_TAKEN), GetAcoreString((mine == AV_NORTH_MINE) ? LANG_BG_AV_MINE_NORTH : LANG_BG_AV_MINE_SOUTH),
|
||||
(teamId == TEAM_ALLIANCE) ? GetAcoreString(LANG_BG_AV_ALLY) : GetAcoreString(LANG_BG_AV_HORDE));
|
||||
sprintf(buf, GetAcoreString(LANG_BG_AV_MINE_TAKEN), (teamId == TEAM_ALLIANCE) ? GetAcoreString(LANG_BG_AV_ALLY) : GetAcoreString(LANG_BG_AV_HORDE),
|
||||
GetAcoreString((mine == AV_NORTH_MINE) ? LANG_BG_AV_MINE_NORTH : LANG_BG_AV_MINE_SOUTH));
|
||||
Creature* creature = GetBGCreature(AV_CPLACE_HERALD);
|
||||
if (creature)
|
||||
YellToAll(creature, buf, LANG_UNIVERSAL);
|
||||
|
||||
@@ -101,6 +101,10 @@ void BattlegroundWS::PostUpdateImpl(uint32 diff)
|
||||
player->CastSpell(player, BG_WS_SPELL_BRUTAL_ASSAULT, true);
|
||||
}
|
||||
break;
|
||||
case BG_WS_EVENT_DESPAWN_DOORS:
|
||||
SpawnBGObject(BG_WS_OBJECT_DOOR_H_1, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(BG_WS_OBJECT_DOOR_H_2, RESPAWN_ONE_DAY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,6 +139,7 @@ void BattlegroundWS::StartingEventOpenDoors()
|
||||
UpdateWorldState(BG_WS_STATE_TIMER_ACTIVE, 1);
|
||||
_bgEvents.ScheduleEvent(BG_WS_EVENT_UPDATE_GAME_TIME, 0);
|
||||
_bgEvents.ScheduleEvent(BG_WS_EVENT_NO_TIME_LEFT, BG_WS_TOTAL_GAME_TIME - 2 * MINUTE * IN_MILLISECONDS); // 27 - 2 = 25 minutes
|
||||
_bgEvents.ScheduleEvent(BG_WS_EVENT_DESPAWN_DOORS, BG_WS_DOOR_DESPAWN_TIME);
|
||||
}
|
||||
|
||||
void BattlegroundWS::AddPlayer(Player* player)
|
||||
|
||||
@@ -30,7 +30,8 @@ enum BG_WS_Events
|
||||
BG_WS_EVENT_ALLIANCE_DROP_FLAG = 4,
|
||||
BG_WS_EVENT_HORDE_DROP_FLAG = 5,
|
||||
BG_WS_EVENT_BOTH_FLAGS_KEPT10 = 6,
|
||||
BG_WS_EVENT_BOTH_FLAGS_KEPT15 = 7
|
||||
BG_WS_EVENT_BOTH_FLAGS_KEPT15 = 7,
|
||||
BG_WS_EVENT_DESPAWN_DOORS = 8
|
||||
};
|
||||
|
||||
enum BG_WS_TimerOrScore
|
||||
@@ -41,7 +42,8 @@ enum BG_WS_TimerOrScore
|
||||
BG_WS_FLAG_RESPAWN_TIME = 23 * IN_MILLISECONDS,
|
||||
BG_WS_FLAG_DROP_TIME = 10 * IN_MILLISECONDS,
|
||||
BG_WS_SPELL_FORCE_TIME = 10 * MINUTE * IN_MILLISECONDS,
|
||||
BG_WS_SPELL_BRUTAL_TIME = 15 * MINUTE * IN_MILLISECONDS
|
||||
BG_WS_SPELL_BRUTAL_TIME = 15 * MINUTE * IN_MILLISECONDS,
|
||||
BG_WS_DOOR_DESPAWN_TIME = 5 * IN_MILLISECONDS
|
||||
};
|
||||
|
||||
enum BG_WS_BroadcastTexts
|
||||
|
||||
@@ -2302,11 +2302,6 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
|
||||
break;
|
||||
case CONDITION_WORLD_STATE:
|
||||
{
|
||||
if (!sWorld->getWorldState(cond->ConditionValue1))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "World state condition has non existing world state in value1 ({}), skipped", cond->ConditionValue1);
|
||||
return false;
|
||||
}
|
||||
if (cond->ConditionValue3)
|
||||
LOG_ERROR("sql.sql", "World state condition has useless data in value3 ({})!", cond->ConditionValue3);
|
||||
break;
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace lfg
|
||||
sLFGMgr->LeaveLfg(player->GetGUID());
|
||||
sLFGMgr->LeaveAllLfgQueues(player->GetGUID(), true);
|
||||
player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW);
|
||||
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, 0.0f);
|
||||
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->m_homebindO);
|
||||
LOG_DEBUG("lfg", "LFGPlayerScript::OnMapChanged, Player {} ({}) is in LFG dungeon map but does not have a valid group! Teleporting to homebind.",
|
||||
player->GetName(), player->GetGUID().ToString());
|
||||
return;
|
||||
|
||||
@@ -646,7 +646,7 @@ void Creature::Update(uint32 diff)
|
||||
if (!allowed) // Will be rechecked on next Update call
|
||||
break;
|
||||
|
||||
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(GetEntry(), m_spawnId);
|
||||
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(m_creatureData ? m_creatureData->id1 : GetEntry(), m_spawnId);
|
||||
time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid);
|
||||
if (!linkedRespawntime) // Can respawn
|
||||
Respawn();
|
||||
@@ -1139,8 +1139,6 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, u
|
||||
break;
|
||||
}
|
||||
|
||||
LoadCreaturesAddon();
|
||||
|
||||
uint32 displayID = GetNativeDisplayId();
|
||||
if (sObjectMgr->GetCreatureModelRandomGender(&displayID) && !IsTotem()) // Cancel load if no model defined or if totem
|
||||
{
|
||||
@@ -1148,6 +1146,8 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, u
|
||||
SetNativeDisplayId(displayID);
|
||||
}
|
||||
|
||||
LoadCreaturesAddon();
|
||||
|
||||
//! Need to be called after LoadCreaturesAddon - MOVEMENTFLAG_HOVER is set there
|
||||
m_positionZ += GetHoverHeight();
|
||||
|
||||
@@ -2032,11 +2032,15 @@ void Creature::Respawn(bool force)
|
||||
setDeathState(JUST_RESPAWNED);
|
||||
|
||||
// MDic - Acidmanifesto
|
||||
uint32 displayID = GetNativeDisplayId();
|
||||
if (sObjectMgr->GetCreatureModelRandomGender(&displayID)) // Cancel load if no model defined
|
||||
// Do not override transform auras
|
||||
if (GetAuraEffectsByType(SPELL_AURA_TRANSFORM).empty())
|
||||
{
|
||||
SetDisplayId(displayID);
|
||||
SetNativeDisplayId(displayID);
|
||||
uint32 displayID = GetNativeDisplayId();
|
||||
if (sObjectMgr->GetCreatureModelRandomGender(&displayID)) // Cancel load if no model defined
|
||||
{
|
||||
SetDisplayId(displayID);
|
||||
SetNativeDisplayId(displayID);
|
||||
}
|
||||
}
|
||||
|
||||
GetMotionMaster()->InitDefault();
|
||||
@@ -2157,7 +2161,7 @@ void Creature::LoadSpellTemplateImmunity()
|
||||
}
|
||||
}
|
||||
|
||||
bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo)
|
||||
bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
|
||||
{
|
||||
if (!spellInfo)
|
||||
return false;
|
||||
@@ -2179,7 +2183,7 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo)
|
||||
if (immunedToAllEffects)
|
||||
return true;
|
||||
|
||||
return Unit::IsImmunedToSpell(spellInfo);
|
||||
return Unit::IsImmunedToSpell(spellInfo, spell);
|
||||
}
|
||||
|
||||
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const
|
||||
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
[[nodiscard]] bool IsValidTrainerForPlayer(Player* player, uint32* npcFlags = nullptr) const;
|
||||
bool CanCreatureAttack(Unit const* victim, bool skipDistCheck = false) const;
|
||||
void LoadSpellTemplateImmunity();
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo) override;
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell = nullptr) override;
|
||||
|
||||
[[nodiscard]] bool HasMechanicTemplateImmunity(uint32 mask) const;
|
||||
// redefine Unit::IsImmunedToSpell
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
return (getLevel() / 2 + uint32(GetStat(STAT_STRENGTH) / 20));
|
||||
}
|
||||
|
||||
[[nodiscard]] SpellSchoolMask GetMeleeDamageSchoolMask() const override { return m_meleeDamageSchoolMask; }
|
||||
[[nodiscard]] SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType /*attackType*/ = BASE_ATTACK, uint8 /*damageIndex*/ = 0) const override { return m_meleeDamageSchoolMask; }
|
||||
void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }
|
||||
|
||||
void _AddCreatureSpellCooldown(uint32 spell_id, uint16 categoryId, uint32 end_time);
|
||||
@@ -178,7 +178,7 @@ public:
|
||||
void UpdateMaxHealth() override;
|
||||
void UpdateMaxPower(Powers power) override;
|
||||
void UpdateAttackPowerAndDamage(bool ranged = false) override;
|
||||
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override;
|
||||
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
|
||||
|
||||
void SetCanDualWield(bool value) override;
|
||||
[[nodiscard]] int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
|
||||
|
||||
@@ -370,11 +370,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
|
||||
// 0x08000000
|
||||
if (unit->m_movementInfo.GetMovementFlags() & MOVEMENTFLAG_SPLINE_ENABLED)
|
||||
{
|
||||
const G3D::Vector3* p = &unit->movespline->_Spline().getPoints(true)[0];
|
||||
if (unit->movespline->_Spline().getPoints(true).empty() || (!unit->movespline->_Spline().getPoints(true).empty() && !p))
|
||||
const_cast<Unit*>(unit)->DisableSpline();
|
||||
else
|
||||
Movement::PacketBuilder::WriteCreate(*unit->movespline, *data);
|
||||
Movement::PacketBuilder::WriteCreate(*unit->movespline, *data);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1237,11 +1233,11 @@ bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool
|
||||
return distsq < maxdist * maxdist;
|
||||
}
|
||||
|
||||
Position WorldObject::GetHitSpherePointFor(Position const& dest, Optional<float> collisionHeight) const
|
||||
Position WorldObject::GetHitSpherePointFor(Position const& dest, Optional<float> collisionHeight, Optional<float> combatReach) const
|
||||
{
|
||||
G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ() + (collisionHeight ? *collisionHeight : GetCollisionHeight()));
|
||||
G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
|
||||
G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(this), GetCombatReach());
|
||||
G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(this), (combatReach ? *combatReach : GetCombatReach()));
|
||||
|
||||
return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAngle(contactPoint.x, contactPoint.y));
|
||||
}
|
||||
@@ -1348,7 +1344,7 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz, VMAP::ModelIgnoreFla
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorldObject::IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlags ignoreFlags, LineOfSightChecks checks, Optional<float> collisionHeight /*= {}*/) const
|
||||
bool WorldObject::IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlags ignoreFlags, LineOfSightChecks checks, Optional<float> collisionHeight /*= { }*/, Optional<float> combatReach /*= { }*/) const
|
||||
{
|
||||
if (!IsInMap(obj))
|
||||
return false;
|
||||
@@ -1369,14 +1365,14 @@ bool WorldObject::IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlag
|
||||
z += GetCollisionHeight();
|
||||
}
|
||||
else
|
||||
GetHitSpherePointFor({ obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ() + obj->GetCollisionHeight() }, x, y, z, collisionHeight);
|
||||
GetHitSpherePointFor({ obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ() + obj->GetCollisionHeight() }, x, y, z, collisionHeight, combatReach);
|
||||
|
||||
return GetMap()->isInLineOfSight(x, y, z, ox, oy, oz, GetPhaseMask(), checks, ignoreFlags);
|
||||
}
|
||||
|
||||
void WorldObject::GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z, Optional<float> collisionHeight) const
|
||||
void WorldObject::GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z, Optional<float> collisionHeight, Optional<float> combatReach) const
|
||||
{
|
||||
Position pos = GetHitSpherePointFor(dest, collisionHeight);
|
||||
Position pos = GetHitSpherePointFor(dest, collisionHeight, combatReach);
|
||||
x = pos.GetPositionX();
|
||||
y = pos.GetPositionY();
|
||||
z = pos.GetPositionZ();
|
||||
|
||||
@@ -465,9 +465,9 @@ public:
|
||||
bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true, bool useBoundingRadius = true) const;
|
||||
bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true, bool useBoundingRadius = true) const;
|
||||
[[nodiscard]] bool IsWithinLOS(float x, float y, float z, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS) const;
|
||||
[[nodiscard]] bool IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS, Optional<float> collisionHeight = { }) const;
|
||||
[[nodiscard]] Position GetHitSpherePointFor(Position const& dest, Optional<float> collisionHeight = { }) const;
|
||||
void GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z, Optional<float> collisionHeight = { }) const;
|
||||
[[nodiscard]] bool IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS, Optional<float> collisionHeight = { }, Optional<float> combatReach = { }) const;
|
||||
[[nodiscard]] Position GetHitSpherePointFor(Position const& dest, Optional<float> collisionHeight = { }, Optional<float> combatReach = { }) const;
|
||||
void GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z, Optional<float> collisionHeight = { }, Optional<float> combatReach = { }) const;
|
||||
bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const;
|
||||
bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const;
|
||||
[[nodiscard]] bool IsInRange2d(float x, float y, float minRange, float maxRange) const;
|
||||
|
||||
@@ -1052,7 +1052,14 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
|
||||
uint32 creature_ID = (petType == HUNTER_PET) ? 1 : cinfo->Entry;
|
||||
|
||||
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
|
||||
if (petType == HUNTER_PET)
|
||||
{
|
||||
SetMeleeDamageSchool(SPELL_SCHOOL_NORMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
|
||||
}
|
||||
|
||||
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
|
||||
|
||||
@@ -1492,7 +1499,7 @@ void Pet::_SaveSpellCooldowns(CharacterDatabaseTransaction trans)
|
||||
{
|
||||
m_CreatureSpellCooldowns.erase(itr2);
|
||||
}
|
||||
else if (itr2->second.end <= infTime && (itr2->second.end > (curMSTime + 30 * IN_MILLISECONDS)))
|
||||
else if (itr2->second.end <= infTime)
|
||||
{
|
||||
uint32 cooldown = ((itr2->second.end - curMSTime) / IN_MILLISECONDS) + curTime;
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_SPELL_COOLDOWN);
|
||||
|
||||
@@ -349,6 +349,7 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
|
||||
m_homebindX = 0;
|
||||
m_homebindY = 0;
|
||||
m_homebindZ = 0;
|
||||
m_homebindO = 0;
|
||||
|
||||
m_contestedPvPTimer = 0;
|
||||
|
||||
@@ -1585,7 +1586,7 @@ bool Player::TeleportToEntryPoint()
|
||||
|
||||
if (loc.m_mapId == MAPID_INVALID)
|
||||
{
|
||||
return TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
|
||||
return TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, m_homebindO);
|
||||
}
|
||||
|
||||
return TeleportTo(loc);
|
||||
@@ -4853,7 +4854,7 @@ void Player::RepopAtGraveyard()
|
||||
}
|
||||
}
|
||||
else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
|
||||
TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
|
||||
TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, m_homebindO);
|
||||
|
||||
RemovePlayerFlag(PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
|
||||
}
|
||||
@@ -6742,21 +6743,11 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
|
||||
if (proto->ArcaneRes)
|
||||
HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply);
|
||||
|
||||
WeaponAttackType attType = BASE_ATTACK;
|
||||
|
||||
if (slot == EQUIPMENT_SLOT_RANGED && (
|
||||
proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_THROWN ||
|
||||
proto->InventoryType == INVTYPE_RANGEDRIGHT))
|
||||
uint8 attType = Player::GetAttackBySlot(slot);
|
||||
if (attType != MAX_ATTACK)
|
||||
{
|
||||
attType = RANGED_ATTACK;
|
||||
}
|
||||
else if (slot == EQUIPMENT_SLOT_OFFHAND)
|
||||
{
|
||||
attType = OFF_ATTACK;
|
||||
}
|
||||
|
||||
if (CanUseAttackType(attType))
|
||||
_ApplyWeaponDamage(slot, proto, ssv, apply);
|
||||
}
|
||||
|
||||
// Druids get feral AP bonus from weapon dps (also use DPS from ScalingStatValue)
|
||||
if (getClass() == CLASS_DRUID)
|
||||
@@ -6799,45 +6790,56 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
|
||||
ssv = ScalingStatValue ? sScalingStatValuesStore.LookupEntry(ssd_level) : nullptr;
|
||||
}
|
||||
|
||||
WeaponAttackType attType = BASE_ATTACK;
|
||||
float damage = 0.0f;
|
||||
|
||||
if (slot == EQUIPMENT_SLOT_RANGED && (
|
||||
proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_THROWN ||
|
||||
proto->InventoryType == INVTYPE_RANGEDRIGHT))
|
||||
uint8 attType = Player::GetAttackBySlot(slot);
|
||||
if (!IsInFeralForm() && apply && !CanUseAttackType(attType))
|
||||
{
|
||||
attType = RANGED_ATTACK;
|
||||
}
|
||||
else if (slot == EQUIPMENT_SLOT_OFFHAND)
|
||||
{
|
||||
attType = OFF_ATTACK;
|
||||
return;
|
||||
}
|
||||
|
||||
float minDamage = proto->Damage[0].DamageMin;
|
||||
float maxDamage = proto->Damage[0].DamageMax;
|
||||
|
||||
// If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage
|
||||
if (ssv)
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
|
||||
{
|
||||
int32 extraDPS = ssv->getDPSMod(ScalingStatValue);
|
||||
if (extraDPS)
|
||||
float minDamage = proto->Damage[i].DamageMin;
|
||||
float maxDamage = proto->Damage[i].DamageMax;
|
||||
|
||||
// If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage
|
||||
if (ssv)
|
||||
{
|
||||
float average = extraDPS * proto->Delay / 1000.0f;
|
||||
minDamage = 0.7f * average;
|
||||
maxDamage = 1.3f * average;
|
||||
int32 extraDPS = ssv->getDPSMod(ScalingStatValue);
|
||||
if (extraDPS)
|
||||
{
|
||||
float average = extraDPS * proto->Delay / 1000.0f;
|
||||
minDamage = 0.7f * average;
|
||||
maxDamage = 1.3f * average;
|
||||
}
|
||||
}
|
||||
|
||||
if (apply)
|
||||
{
|
||||
if (minDamage > 0.f)
|
||||
{
|
||||
SetBaseWeaponDamage(WeaponAttackType(attType), MINDAMAGE, minDamage, i);
|
||||
}
|
||||
|
||||
if (maxDamage > 0.f)
|
||||
{
|
||||
SetBaseWeaponDamage(WeaponAttackType(attType), MAXDAMAGE, maxDamage, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minDamage > 0)
|
||||
if (!apply)
|
||||
{
|
||||
damage = apply ? minDamage : BASE_MINDAMAGE;
|
||||
SetBaseWeaponDamage(attType, MINDAMAGE, damage);
|
||||
}
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
|
||||
{
|
||||
SetBaseWeaponDamage(WeaponAttackType(attType), MINDAMAGE, 0.f, i);
|
||||
SetBaseWeaponDamage(WeaponAttackType(attType), MAXDAMAGE, 0.f, i);
|
||||
}
|
||||
|
||||
if (maxDamage > 0)
|
||||
{
|
||||
damage = apply ? maxDamage : BASE_MAXDAMAGE;
|
||||
SetBaseWeaponDamage(attType, MAXDAMAGE, damage);
|
||||
if (attType == BASE_ATTACK)
|
||||
{
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, BASE_MINDAMAGE);
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, BASE_MAXDAMAGE);
|
||||
}
|
||||
}
|
||||
|
||||
if (proto->Delay && !IsInFeralForm())
|
||||
@@ -6854,8 +6856,18 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
|
||||
if (IsInFeralForm())
|
||||
return;
|
||||
|
||||
if (CanModifyStats() && (damage || proto->Delay))
|
||||
UpdateDamagePhysical(attType);
|
||||
if (CanModifyStats() && (GetWeaponDamageRange(WeaponAttackType(attType), MAXDAMAGE) || proto->Delay))
|
||||
UpdateDamagePhysical(WeaponAttackType(attType));
|
||||
}
|
||||
|
||||
SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*= BASE_ATTACK*/, uint8 damageIndex /*= 0*/) const
|
||||
{
|
||||
if (Item const* weapon = GetWeaponForAttack(attackType, true))
|
||||
{
|
||||
return SpellSchoolMask(1 << weapon->GetTemplate()->Damage[damageIndex].DamageType);
|
||||
}
|
||||
|
||||
return SPELL_SCHOOL_MASK_NORMAL;
|
||||
}
|
||||
|
||||
void Player::_ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply)
|
||||
@@ -8688,7 +8700,7 @@ void Player::SendBGWeekendWorldStates()
|
||||
void Player::SendBattlefieldWorldStates()
|
||||
{
|
||||
/// Send misc stuff that needs to be sent on every login, like the battle timers.
|
||||
if (sWorld->getBoolConfig(CONFIG_WINTERGRASP_ENABLE))
|
||||
if (sWorld->getIntConfig(CONFIG_WINTERGRASP_ENABLE) == 1)
|
||||
{
|
||||
if (BattlefieldWG* wg = (BattlefieldWG*)sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG))
|
||||
{
|
||||
@@ -11045,7 +11057,7 @@ void Player::SetEntryPoint()
|
||||
}
|
||||
|
||||
if (m_entryPointData.joinPos.m_mapId == MAPID_INVALID)
|
||||
m_entryPointData.joinPos = WorldLocation(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, 0.0f);
|
||||
m_entryPointData.joinPos = WorldLocation(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, m_homebindO);
|
||||
}
|
||||
|
||||
void Player::LeaveBattleground(Battleground* bg)
|
||||
@@ -13306,14 +13318,21 @@ uint32 Player::CalculateTalentsPoints() const
|
||||
{
|
||||
uint32 base_talent = getLevel() < 10 ? 0 : getLevel() - 9;
|
||||
|
||||
uint32 talentPointsForLevel = 0;
|
||||
if (getClass() != CLASS_DEATH_KNIGHT || GetMapId() != 609)
|
||||
return uint32(base_talent * sWorld->getRate(RATE_TALENT));
|
||||
|
||||
uint32 talentPointsForLevel = getLevel() < 56 ? 0 : getLevel() - 55;
|
||||
talentPointsForLevel += m_questRewardTalentCount;
|
||||
|
||||
if (talentPointsForLevel > base_talent)
|
||||
{
|
||||
talentPointsForLevel = base_talent;
|
||||
}
|
||||
else
|
||||
{
|
||||
talentPointsForLevel = getLevel() < 56 ? 0 : getLevel() - 55;
|
||||
talentPointsForLevel += m_questRewardTalentCount;
|
||||
|
||||
if (talentPointsForLevel > base_talent)
|
||||
{
|
||||
talentPointsForLevel = base_talent;
|
||||
}
|
||||
}
|
||||
|
||||
talentPointsForLevel += m_extraBonusTalentCount;
|
||||
return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT));
|
||||
@@ -13611,16 +13630,23 @@ void Player::CompletedAchievement(AchievementEntry const* entry)
|
||||
m_achievementMgr->CompletedAchievement(entry);
|
||||
}
|
||||
|
||||
void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||
void Player::LearnTalent(uint32 talentId, uint32 talentRank, bool command /*= false*/)
|
||||
{
|
||||
uint32 CurTalentPoints = GetFreeTalentPoints();
|
||||
|
||||
// xinef: check basic data
|
||||
if (CurTalentPoints == 0)
|
||||
return;
|
||||
if (!command)
|
||||
{
|
||||
// xinef: check basic data
|
||||
if (!CurTalentPoints)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (talentRank >= MAX_TALENT_RANK)
|
||||
return;
|
||||
if (talentRank >= MAX_TALENT_RANK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||
if (!talentInfo)
|
||||
@@ -13649,10 +13675,15 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||
if (currentTalentRank >= talentRank + 1)
|
||||
return;
|
||||
|
||||
// xinef: check if we have enough free talent points
|
||||
uint32 talentPointsChange = (talentRank - currentTalentRank + 1);
|
||||
if (CurTalentPoints < talentPointsChange)
|
||||
return;
|
||||
if (!command)
|
||||
{
|
||||
// xinef: check if we have enough free talent points
|
||||
if (CurTalentPoints < talentPointsChange)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// xinef: check if talent deponds on another talent
|
||||
if (talentInfo->DependsOn > 0)
|
||||
@@ -13674,23 +13705,26 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||
return;
|
||||
}
|
||||
|
||||
// xinef: check amount of points spent in current talent tree
|
||||
// xinef: be smart and quick
|
||||
uint32 spentPoints = 0;
|
||||
if (talentInfo->Row > 0)
|
||||
if (!command)
|
||||
{
|
||||
const PlayerTalentMap& talentMap = GetTalentMap();
|
||||
for (PlayerTalentMap::const_iterator itr = talentMap.begin(); itr != talentMap.end(); ++itr)
|
||||
if (TalentSpellPos const* talentPos = GetTalentSpellPos(itr->first))
|
||||
if (TalentEntry const* itrTalentInfo = sTalentStore.LookupEntry(talentPos->talent_id))
|
||||
if (itrTalentInfo->TalentTab == talentInfo->TalentTab)
|
||||
if (itr->second->State != PLAYERSPELL_REMOVED && itr->second->IsInSpec(GetActiveSpec())) // pussywizard
|
||||
spentPoints += talentPos->rank + 1;
|
||||
}
|
||||
// xinef: check amount of points spent in current talent tree
|
||||
// xinef: be smart and quick
|
||||
uint32 spentPoints = 0;
|
||||
if (talentInfo->Row > 0)
|
||||
{
|
||||
const PlayerTalentMap& talentMap = GetTalentMap();
|
||||
for (PlayerTalentMap::const_iterator itr = talentMap.begin(); itr != talentMap.end(); ++itr)
|
||||
if (TalentSpellPos const* talentPos = GetTalentSpellPos(itr->first))
|
||||
if (TalentEntry const* itrTalentInfo = sTalentStore.LookupEntry(talentPos->talent_id))
|
||||
if (itrTalentInfo->TalentTab == talentInfo->TalentTab)
|
||||
if (itr->second->State != PLAYERSPELL_REMOVED && itr->second->IsInSpec(GetActiveSpec())) // pussywizard
|
||||
spentPoints += talentPos->rank + 1;
|
||||
}
|
||||
|
||||
// xinef: we do not have enough talent points to add talent of this tier
|
||||
if (spentPoints < (talentInfo->Row * MAX_TALENT_RANK))
|
||||
return;
|
||||
// xinef: we do not have enough talent points to add talent of this tier
|
||||
if (spentPoints < (talentInfo->Row * MAX_TALENT_RANK))
|
||||
return;
|
||||
}
|
||||
|
||||
// xinef: hacking attempt, tries to learn unknown rank
|
||||
uint32 spellId = talentInfo->RankID[talentRank];
|
||||
@@ -13723,7 +13757,11 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||
|
||||
// xinef: update free talent points count
|
||||
m_usedTalentCount += talentPointsChange;
|
||||
SetFreeTalentPoints(CurTalentPoints - talentPointsChange);
|
||||
|
||||
if (!command)
|
||||
{
|
||||
SetFreeTalentPoints(CurTalentPoints - talentPointsChange);
|
||||
}
|
||||
|
||||
sScriptMgr->OnPlayerLearnTalents(this, talentId, talentRank, spellId);
|
||||
}
|
||||
|
||||
@@ -1677,7 +1677,7 @@ public:
|
||||
void BuildPlayerTalentsInfoData(WorldPacket* data);
|
||||
void BuildPetTalentsInfoData(WorldPacket* data);
|
||||
void SendTalentsInfoData(bool pet);
|
||||
void LearnTalent(uint32 talentId, uint32 talentRank);
|
||||
void LearnTalent(uint32 talentId, uint32 talentRank, bool command = false);
|
||||
void LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRank);
|
||||
|
||||
bool addTalent(uint32 spellId, uint8 addSpecMask, uint8 oldTalentRank);
|
||||
@@ -1905,7 +1905,7 @@ public:
|
||||
void UpdateRating(CombatRating cr);
|
||||
void UpdateAllRatings();
|
||||
|
||||
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override;
|
||||
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
|
||||
|
||||
void UpdateDefenseBonusesMod();
|
||||
inline void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);}
|
||||
@@ -2147,6 +2147,8 @@ public:
|
||||
|
||||
void ResetAllPowers();
|
||||
|
||||
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const override;
|
||||
|
||||
void _ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply);
|
||||
void _ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
|
||||
void _ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
|
||||
@@ -2317,6 +2319,7 @@ public:
|
||||
float m_homebindX;
|
||||
float m_homebindY;
|
||||
float m_homebindZ;
|
||||
float m_homebindO;
|
||||
|
||||
[[nodiscard]] WorldLocation GetStartPosition() const;
|
||||
|
||||
|
||||
@@ -78,6 +78,13 @@ PlayerSetting Player::GetPlayerSetting(std::string source, uint8 index)
|
||||
return GetPlayerSetting(source, index);
|
||||
}
|
||||
|
||||
PlayerSettingVector settingVector = itr->second;
|
||||
if (settingVector.size() < (uint8)(index + 1))
|
||||
{
|
||||
UpdatePlayerSetting(source, index, 0);
|
||||
return GetPlayerSetting(source, index);
|
||||
}
|
||||
|
||||
return itr->second[index];
|
||||
}
|
||||
|
||||
|
||||
@@ -2593,6 +2593,8 @@ Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update
|
||||
stmt->SetData(1, ss.str());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
sScriptMgr->OnStoreNewItem(this, pItem, count);
|
||||
}
|
||||
return pItem;
|
||||
}
|
||||
@@ -4922,7 +4924,7 @@ bool Player::LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, flo
|
||||
|
||||
void Player::SetHomebind(WorldLocation const& loc, uint32 areaId)
|
||||
{
|
||||
loc.GetPosition(m_homebindX, m_homebindY, m_homebindZ);
|
||||
loc.GetPosition(m_homebindX, m_homebindY, m_homebindZ, m_homebindO);
|
||||
m_homebindMapId = loc.GetMapId();
|
||||
m_homebindAreaId = areaId;
|
||||
|
||||
@@ -4930,10 +4932,11 @@ void Player::SetHomebind(WorldLocation const& loc, uint32 areaId)
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_HOMEBIND);
|
||||
stmt->SetData(0, m_homebindMapId);
|
||||
stmt->SetData(1, m_homebindAreaId);
|
||||
stmt->SetData (2, m_homebindX);
|
||||
stmt->SetData (3, m_homebindY);
|
||||
stmt->SetData (4, m_homebindZ);
|
||||
stmt->SetData(5, GetGUID().GetCounter());
|
||||
stmt->SetData(2, m_homebindX);
|
||||
stmt->SetData(3, m_homebindY);
|
||||
stmt->SetData(4, m_homebindZ);
|
||||
stmt->SetData(5, m_homebindO);
|
||||
stmt->SetData(6, GetGUID().GetCounter());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
@@ -5104,7 +5107,7 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
|
||||
std::string taxi_nodes = fields[42].Get<std::string>();
|
||||
|
||||
auto RelocateToHomebind = [this, &mapId, &instanceId]() { mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); };
|
||||
auto RelocateToHomebind = [this, &mapId, &instanceId]() { mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ, m_homebindO); };
|
||||
|
||||
_LoadGroup();
|
||||
|
||||
@@ -5426,7 +5429,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
? bubble1 * sWorld->getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY)
|
||||
: bubble0 * sWorld->getRate(RATE_REST_OFFLINE_IN_WILDERNESS);
|
||||
|
||||
SetRestBonus(GetRestBonus() + time_diff * ((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 72000)*bubble);
|
||||
// Client automatically doubles the value sent so we have to divide it by 2
|
||||
SetRestBonus(GetRestBonus() + time_diff * ((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 144000)*bubble);
|
||||
}
|
||||
|
||||
uint32 innTriggerId = fields[72].Get<uint32>();
|
||||
@@ -7004,7 +7008,7 @@ bool Player::_LoadHomeBind(PreparedQueryResult result)
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
// SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?
|
||||
// SELECT mapId, zoneId, posX, posY, posZ, pozO FROM character_homebind WHERE guid = ?
|
||||
if (result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
@@ -7014,11 +7018,12 @@ bool Player::_LoadHomeBind(PreparedQueryResult result)
|
||||
m_homebindX = fields[2].Get<float>();
|
||||
m_homebindY = fields[3].Get<float>();
|
||||
m_homebindZ = fields[4].Get<float>();
|
||||
m_homebindO = fields[5].Get<float>();
|
||||
|
||||
MapEntry const* bindMapEntry = sMapStore.LookupEntry(m_homebindMapId);
|
||||
|
||||
// accept saved data only for valid position (and non instanceable), and accessable
|
||||
if (MapMgr::IsValidMapCoord(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ) &&
|
||||
if (MapMgr::IsValidMapCoord(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, m_homebindO) &&
|
||||
!bindMapEntry->Instanceable() && GetSession()->Expansion() >= bindMapEntry->Expansion())
|
||||
ok = true;
|
||||
else
|
||||
@@ -7036,19 +7041,20 @@ bool Player::_LoadHomeBind(PreparedQueryResult result)
|
||||
m_homebindX = info->positionX;
|
||||
m_homebindY = info->positionY;
|
||||
m_homebindZ = info->positionZ;
|
||||
|
||||
m_homebindO = info->orientation;
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND);
|
||||
stmt->SetData(0, GetGUID().GetCounter());
|
||||
stmt->SetData(1, m_homebindMapId);
|
||||
stmt->SetData(2, m_homebindAreaId);
|
||||
stmt->SetData (3, m_homebindX);
|
||||
stmt->SetData (4, m_homebindY);
|
||||
stmt->SetData (5, m_homebindZ);
|
||||
stmt->SetData(3, m_homebindX);
|
||||
stmt->SetData(4, m_homebindY);
|
||||
stmt->SetData(5, m_homebindZ);
|
||||
stmt->SetData(6, m_homebindO);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
LOG_DEBUG("entities.player", "Setting player home position - mapid: {}, areaid: {}, X: {}, Y: {}, Z: {}",
|
||||
m_homebindMapId, m_homebindAreaId, m_homebindX, m_homebindY, m_homebindZ);
|
||||
LOG_DEBUG("entities.player", "Setting player home position - mapid: {}, areaid: {}, X: {}, Y: {}, Z: {}, O: {}",
|
||||
m_homebindMapId, m_homebindAreaId, m_homebindX, m_homebindY, m_homebindZ, m_homebindO);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1019,7 +1019,7 @@ void Player::UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool def
|
||||
|
||||
chance = chance < 1.0f ? 1.0f : chance; // minimum chance to increase skill is 1%
|
||||
|
||||
LOG_DEBUG("entities.player", "Player::UpdateCombatSkills(defence:{}, playerLevel:{}, moblevel:{}) -> ({}/{}) chance to increase skill is {}\%", defence, playerLevel, moblevel, currentSkillValue, currentSkillMax, chance);
|
||||
LOG_DEBUG("entities.player", "Player::UpdateCombatSkills(defence:{}, playerLevel:{}, moblevel:{}) -> ({}/{}) chance to increase skill is {}%", defence, playerLevel, moblevel, currentSkillValue, currentSkillMax, chance);
|
||||
|
||||
if (roll_chance_f(chance))
|
||||
{
|
||||
|
||||
@@ -59,25 +59,31 @@ void Unit::UpdateAllResistances()
|
||||
|
||||
void Unit::UpdateDamagePhysical(WeaponAttackType attType)
|
||||
{
|
||||
float minDamage = 0.0f;
|
||||
float maxDamage = 0.0f;
|
||||
float totalMin = 0.f;
|
||||
float totalMax = 0.f;
|
||||
|
||||
CalculateMinMaxDamage(attType, false, true, minDamage, maxDamage);
|
||||
float tmpMin, tmpMax;
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
|
||||
{
|
||||
CalculateMinMaxDamage(attType, false, true, tmpMin, tmpMax, i);
|
||||
totalMin += tmpMin;
|
||||
totalMax += tmpMax;
|
||||
}
|
||||
|
||||
switch (attType)
|
||||
{
|
||||
case BASE_ATTACK:
|
||||
default:
|
||||
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, minDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, totalMin);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, totalMax);
|
||||
break;
|
||||
case OFF_ATTACK:
|
||||
SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, minDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, maxDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, totalMin);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, totalMax);
|
||||
break;
|
||||
case RANGED_ATTACK:
|
||||
SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, minDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, maxDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, totalMin);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, totalMax);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -525,8 +531,23 @@ void Player::UpdateShieldBlockValue()
|
||||
SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
|
||||
}
|
||||
|
||||
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
|
||||
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex)
|
||||
{
|
||||
// Only proto damage, not affected by any mods
|
||||
if (damageIndex != 0)
|
||||
{
|
||||
minDamage = 0.0f;
|
||||
maxDamage = 0.0f;
|
||||
|
||||
if (!IsInFeralForm() && CanUseAttackType(attType))
|
||||
{
|
||||
minDamage = GetWeaponDamageRange(attType, MINDAMAGE, damageIndex);
|
||||
maxDamage = GetWeaponDamageRange(attType, MAXDAMAGE, damageIndex);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UnitMods unitMod;
|
||||
|
||||
switch (attType)
|
||||
@@ -1075,8 +1096,16 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
|
||||
void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex /*= 0*/)
|
||||
{
|
||||
// creatures only have one damage
|
||||
if (damageIndex != 0)
|
||||
{
|
||||
minDamage = 0.f;
|
||||
maxDamage = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
UnitMods unitMod;
|
||||
float variance = 1.0f;
|
||||
switch (attType)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,7 @@
|
||||
#include "FollowerRefMgr.h"
|
||||
#include "FollowerReference.h"
|
||||
#include "HostileRefMgr.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "Object.h"
|
||||
#include "Optional.h"
|
||||
@@ -251,7 +252,9 @@ enum UnitModifierType
|
||||
enum WeaponDamageRange
|
||||
{
|
||||
MINDAMAGE,
|
||||
MAXDAMAGE
|
||||
MAXDAMAGE,
|
||||
|
||||
MAX_WEAPON_DAMAGE_RANGE
|
||||
};
|
||||
|
||||
enum UnitMods
|
||||
@@ -714,6 +717,12 @@ enum MeleeHitOutcome
|
||||
MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL
|
||||
};
|
||||
|
||||
enum ExtraAttackSpells
|
||||
{
|
||||
SPELL_SWORD_SPECIALIZATION = 16459,
|
||||
SPELL_HACK_AND_SLASH = 66923
|
||||
};
|
||||
|
||||
class DispelInfo
|
||||
{
|
||||
public:
|
||||
@@ -762,9 +771,14 @@ private:
|
||||
uint32 m_resist;
|
||||
uint32 m_block;
|
||||
uint32 m_cleanDamage;
|
||||
|
||||
// amalgamation constructor (used for proc)
|
||||
DamageInfo(DamageInfo const& dmg1, DamageInfo const& dmg2);
|
||||
|
||||
public:
|
||||
explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType, uint32 cleanDamage = 0);
|
||||
explicit DamageInfo(CalcDamageInfo& dmgInfo);
|
||||
explicit DamageInfo(CalcDamageInfo const& dmgInfo); // amalgamation wrapper
|
||||
DamageInfo(CalcDamageInfo const& dmgInfo, uint8 damageIndex);
|
||||
DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType);
|
||||
|
||||
void ModifyDamage(int32 amount);
|
||||
@@ -868,10 +882,15 @@ struct CalcDamageInfo
|
||||
{
|
||||
Unit* attacker; // Attacker
|
||||
Unit* target; // Target for damage
|
||||
uint32 damageSchoolMask;
|
||||
uint32 damage;
|
||||
uint32 absorb;
|
||||
uint32 resist;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 damageSchoolMask;
|
||||
uint32 damage;
|
||||
uint32 absorb;
|
||||
uint32 resist;
|
||||
} damages[MAX_ITEM_PROTO_DAMAGES];
|
||||
|
||||
uint32 blocked_amount;
|
||||
uint32 HitInfo;
|
||||
uint32 TargetState;
|
||||
@@ -1331,7 +1350,7 @@ public:
|
||||
bool IsWithinCombatRange(Unit const* obj, float dist2compare) const;
|
||||
bool IsWithinMeleeRange(Unit const* obj, float dist = 0.f) const;
|
||||
float GetMeleeRange(Unit const* target) const;
|
||||
[[nodiscard]] virtual SpellSchoolMask GetMeleeDamageSchoolMask() const;
|
||||
virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const = 0;
|
||||
bool GetRandomContactPoint(Unit const* target, float& x, float& y, float& z, bool force = false) const;
|
||||
uint32 m_extraAttacks;
|
||||
bool m_canDualWield;
|
||||
@@ -1541,7 +1560,7 @@ public:
|
||||
void HandleEmoteCommand(uint32 emoteId);
|
||||
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false, bool ignoreCasting = false);
|
||||
|
||||
void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false);
|
||||
void CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false);
|
||||
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
|
||||
|
||||
void HandleProcExtraAttackFor(Unit* victim, uint32 count);
|
||||
@@ -1571,10 +1590,11 @@ public:
|
||||
|
||||
static void ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type);
|
||||
|
||||
float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
|
||||
SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spell);
|
||||
SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spell);
|
||||
SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spell, bool canReflect = false);
|
||||
[[nodiscard]] float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
|
||||
[[nodiscard]] SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spell);
|
||||
[[nodiscard]] SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spell);
|
||||
[[nodiscard]] SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spell, bool canReflect = false);
|
||||
[[nodiscard]] SpellMissInfo SpellHitResult(Unit* victim, Spell const* spell, bool canReflect = false);
|
||||
|
||||
[[nodiscard]] float GetUnitDodgeChance() const;
|
||||
[[nodiscard]] float GetUnitParryChance() const;
|
||||
@@ -1732,7 +1752,7 @@ public:
|
||||
void SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount);
|
||||
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage* log);
|
||||
void SendSpellNonMeleeReflectLog(SpellNonMeleeDamage* log, Unit* attacker);
|
||||
void SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false);
|
||||
void SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false, bool Split = false);
|
||||
void SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo);
|
||||
void SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo);
|
||||
void SendSpellDamageResist(Unit* target, uint32 spellId);
|
||||
@@ -2093,10 +2113,10 @@ public:
|
||||
virtual void UpdateAttackPowerAndDamage(bool ranged = false) = 0;
|
||||
virtual void UpdateDamagePhysical(WeaponAttackType attType);
|
||||
float GetTotalAttackPowerValue(WeaponAttackType attType, Unit* pVictim = nullptr) const;
|
||||
[[nodiscard]] float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const;
|
||||
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; }
|
||||
virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) = 0;
|
||||
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct);
|
||||
[[nodiscard]] float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex = 0) const;
|
||||
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value, uint8 damageIndex = 0) { m_weaponDamage[attType][damageRange][damageIndex] = value; }
|
||||
virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex = 0) = 0;
|
||||
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, uint8 itemDamagesMask = 0);
|
||||
float GetAPMultiplier(WeaponAttackType attType, bool normalized);
|
||||
|
||||
bool isInFrontInMap(Unit const* target, float distance, float arc = M_PI) const;
|
||||
@@ -2181,8 +2201,8 @@ public:
|
||||
uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint8 effIndex, float TotalMod = 0.0f, uint32 stack = 1);
|
||||
uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1);
|
||||
|
||||
uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = nullptr);
|
||||
uint32 MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto = nullptr);
|
||||
uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = nullptr, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL);
|
||||
uint32 MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto = nullptr, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL);
|
||||
|
||||
bool isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType = BASE_ATTACK);
|
||||
bool isBlockCritical();
|
||||
@@ -2203,12 +2223,14 @@ public:
|
||||
|
||||
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply, SpellImmuneBlockType blockType = SPELL_BLOCK_TYPE_ALL);
|
||||
void ApplySpellDispelImmunity(SpellInfo const* spellProto, DispelType type, bool apply);
|
||||
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo);
|
||||
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell = nullptr);
|
||||
// redefined in Creature
|
||||
[[nodiscard]] bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const;
|
||||
bool IsImmunedToDamage(SpellInfo const* spellInfo) const;
|
||||
[[nodiscard]] bool IsImmunedToDamage(SpellInfo const* spellInfo) const;
|
||||
[[nodiscard]] bool IsImmunedToDamage(Spell const* spell) const;
|
||||
[[nodiscard]] bool IsImmunedToSchool(SpellSchoolMask meleeSchoolMask) const;
|
||||
bool IsImmunedToSchool(SpellInfo const* spellInfo) const;
|
||||
[[nodiscard]] bool IsImmunedToSchool(SpellInfo const* spellInfo) const;
|
||||
[[nodiscard]] bool IsImmunedToSchool(Spell const* spell) const;
|
||||
[[nodiscard]] bool IsImmunedToDamageOrSchool(SpellSchoolMask meleeSchoolMask) const;
|
||||
bool IsImmunedToDamageOrSchool(SpellInfo const* spellInfo) const;
|
||||
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const;
|
||||
@@ -2490,7 +2512,7 @@ protected:
|
||||
uint32 m_interruptMask;
|
||||
|
||||
float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END];
|
||||
float m_weaponDamage[MAX_ATTACK][2];
|
||||
float m_weaponDamage[MAX_ATTACK][MAX_WEAPON_DAMAGE_RANGE][MAX_ITEM_PROTO_DAMAGES];
|
||||
bool m_canModifyStats;
|
||||
VisibleAuraMap m_visibleAuras;
|
||||
|
||||
|
||||
@@ -100,6 +100,11 @@ namespace PlayerNameMapHolder
|
||||
PlayerNameMap.erase(p->GetName());
|
||||
}
|
||||
|
||||
void RemoveByName(std::string const& name)
|
||||
{
|
||||
PlayerNameMap.erase(name);
|
||||
}
|
||||
|
||||
Player* Find(std::string const& name)
|
||||
{
|
||||
std::string charName(name);
|
||||
@@ -290,3 +295,9 @@ void ObjectAccessor::RemoveObject(Player* player)
|
||||
HashMapHolder<Player>::Remove(player);
|
||||
PlayerNameMapHolder::Remove(player);
|
||||
}
|
||||
|
||||
void ObjectAccessor::UpdatePlayerNameMapReference(std::string oldname, Player* player)
|
||||
{
|
||||
PlayerNameMapHolder::RemoveByName(oldname);
|
||||
PlayerNameMapHolder::Insert(player);
|
||||
}
|
||||
|
||||
@@ -106,6 +106,8 @@ namespace ObjectAccessor
|
||||
|
||||
template<>
|
||||
void RemoveObject(Player* player);
|
||||
|
||||
void UpdatePlayerNameMapReference(std::string oldname, Player* player);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6320,7 +6320,7 @@ void ObjectMgr::LoadTavernAreaTriggers()
|
||||
|
||||
_tavernAreaTriggerStore.clear(); // need for reload case
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern");
|
||||
QueryResult result = WorldDatabase.Query("SELECT id, faction FROM areatrigger_tavern");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -6346,7 +6346,9 @@ void ObjectMgr::LoadTavernAreaTriggers()
|
||||
continue;
|
||||
}
|
||||
|
||||
_tavernAreaTriggerStore.insert(Trigger_ID);
|
||||
uint32 faction = fields[1].Get<uint32>();
|
||||
|
||||
_tavernAreaTriggerStore.emplace(Trigger_ID, faction);
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Tavern Triggers in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
@@ -840,9 +840,15 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsTavernAreaTrigger(uint32 Trigger_ID) const
|
||||
[[nodiscard]] bool IsTavernAreaTrigger(uint32 triggerID, uint32 faction) const
|
||||
{
|
||||
return _tavernAreaTriggerStore.find(Trigger_ID) != _tavernAreaTriggerStore.end();
|
||||
auto itr = _tavernAreaTriggerStore.find(triggerID);
|
||||
if (itr != _tavernAreaTriggerStore.end())
|
||||
{
|
||||
return (itr->second & faction) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] GossipText const* GetGossipText(uint32 Text_ID) const;
|
||||
@@ -1449,7 +1455,7 @@ private:
|
||||
|
||||
typedef std::unordered_map<uint32, GossipText> GossipTextContainer;
|
||||
typedef std::unordered_map<uint32, uint32> QuestAreaTriggerContainer;
|
||||
typedef std::set<uint32> TavernAreaTriggerContainer;
|
||||
typedef std::unordered_map<uint32, uint32> TavernAreaTriggerContainer;
|
||||
|
||||
QuestAreaTriggerContainer _questAreaTriggerStore;
|
||||
TavernAreaTriggerContainer _tavernAreaTriggerStore;
|
||||
|
||||
@@ -1827,8 +1827,14 @@ void Guild::SendBankTabData(WorldSession* session, uint8 tabId, bool sendAllSlot
|
||||
_SendBankContent(session, tabId, sendAllSlots);
|
||||
}
|
||||
|
||||
void Guild::SendBankTabsInfo(WorldSession* session, bool sendAllSlots /*= false*/) const
|
||||
void Guild::SendBankTabsInfo(WorldSession* session, bool sendAllSlots /*= false*/)
|
||||
{
|
||||
Member* member = GetMember(session->GetPlayer()->GetGUID());
|
||||
if (!member)
|
||||
return;
|
||||
|
||||
member->SubscribeToGuildBankUpdatePackets();
|
||||
|
||||
_SendBankList(session, 0, sendAllSlots);
|
||||
}
|
||||
|
||||
@@ -1838,12 +1844,17 @@ void Guild::SendBankTabText(WorldSession* session, uint8 tabId) const
|
||||
tab->SendText(this, session);
|
||||
}
|
||||
|
||||
void Guild::SendPermissions(WorldSession* session) const
|
||||
void Guild::SendPermissions(WorldSession* session)
|
||||
{
|
||||
Member const* member = GetMember(session->GetPlayer()->GetGUID());
|
||||
Member* member = GetMember(session->GetPlayer()->GetGUID());
|
||||
if (!member)
|
||||
return;
|
||||
|
||||
// We are unsubscribing here since it is the only reliable way to handle /reload from player as
|
||||
// GuildPermissionsQuery is sent on each reload, and we don't want to send partial changes while client
|
||||
// doesn't know the full state
|
||||
member->UnsubscribeFromGuildBankUpdatePackets();
|
||||
|
||||
uint8 rankId = member->GetRankId();
|
||||
|
||||
WorldPackets::Guild::GuildPermissionsQueryResults queryResult;
|
||||
@@ -1886,8 +1897,6 @@ void Guild::SendLoginInfo(WorldSession* session)
|
||||
|
||||
LOG_DEBUG("guild", "SMSG_GUILD_EVENT [{}] MOTD", session->GetPlayerInfo());
|
||||
|
||||
SendBankTabsInfo(session);
|
||||
|
||||
Player* player = session->GetPlayer();
|
||||
|
||||
HandleRoster(session);
|
||||
@@ -2920,13 +2929,17 @@ void Guild::_SendBankList(WorldSession* session /* = nullptr*/, uint8 tabId /*=
|
||||
LOG_DEBUG("guild", "SMSG_GUILD_BANK_LIST [{}]: TabId: {}, FullSlots: {}, slots: {}",
|
||||
session->GetPlayerInfo(), tabId, sendAllSlots, packet.WithdrawalsRemaining);
|
||||
}
|
||||
else /// @todo - Probably this is just sent to session + those that have sent CMSG_GUILD_BANKER_ACTIVATE
|
||||
else
|
||||
{
|
||||
packet.Write();
|
||||
for (auto const& [guid, member] : m_members)
|
||||
{
|
||||
if (!member.ShouldReceiveBankPartialUpdatePackets())
|
||||
continue;
|
||||
|
||||
if (!MemberHasTabRights(member.GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB))
|
||||
continue;
|
||||
|
||||
Player* player = member.FindPlayer();
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
@@ -307,7 +307,8 @@ public: // pussywizard: public class Member
|
||||
m_class(0),
|
||||
m_flags(GUILDMEMBER_STATUS_NONE),
|
||||
m_accountId(0),
|
||||
m_rankId(rankId)
|
||||
m_rankId(rankId),
|
||||
receiveGuildBankUpdatePackets(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -354,6 +355,10 @@ public: // pussywizard: public class Member
|
||||
|
||||
inline Player* FindPlayer() const { return ObjectAccessor::FindConnectedPlayer(m_guid); }
|
||||
|
||||
void SubscribeToGuildBankUpdatePackets() { receiveGuildBankUpdatePackets = true; }
|
||||
void UnsubscribeFromGuildBankUpdatePackets() { receiveGuildBankUpdatePackets = false; }
|
||||
[[nodiscard]] bool ShouldReceiveBankPartialUpdatePackets() const { return receiveGuildBankUpdatePackets; }
|
||||
|
||||
private:
|
||||
uint32 m_guildId;
|
||||
// Fields from characters table
|
||||
@@ -372,6 +377,8 @@ public: // pussywizard: public class Member
|
||||
std::string m_officerNote;
|
||||
|
||||
std::array<int32, GUILD_BANK_MAX_TABS + 1> m_bankWithdraw = {};
|
||||
|
||||
bool receiveGuildBankUpdatePackets;
|
||||
};
|
||||
|
||||
// pussywizard: public GetMember
|
||||
@@ -721,10 +728,10 @@ public:
|
||||
void SendInfo(WorldSession* session) const;
|
||||
void SendEventLog(WorldSession* session) const;
|
||||
void SendBankLog(WorldSession* session, uint8 tabId) const;
|
||||
void SendBankTabsInfo(WorldSession* session, bool showTabs = false) const;
|
||||
void SendBankTabsInfo(WorldSession* session, bool showTabs = false);
|
||||
void SendBankTabData(WorldSession* session, uint8 tabId, bool sendAllSlots) const;
|
||||
void SendBankTabText(WorldSession* session, uint8 tabId) const;
|
||||
void SendPermissions(WorldSession* session) const;
|
||||
void SendPermissions(WorldSession* session);
|
||||
void SendMoneyInfo(WorldSession* session) const;
|
||||
void SendLoginInfo(WorldSession* session);
|
||||
|
||||
|
||||
@@ -888,7 +888,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
|
||||
if (at)
|
||||
pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation());
|
||||
else
|
||||
pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation());
|
||||
pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->m_homebindO);
|
||||
}
|
||||
|
||||
pCurrChar->SendInitialPacketsAfterAddToMap();
|
||||
@@ -2338,6 +2338,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact
|
||||
stmt->SetData(3, loc.GetPositionX());
|
||||
stmt->SetData(4, loc.GetPositionY());
|
||||
stmt->SetData(5, loc.GetPositionZ());
|
||||
stmt->SetData(6, loc.GetOrientation());
|
||||
trans->Append(stmt);
|
||||
|
||||
Player::SavePositionInDB(loc, zoneId, factionChangeInfo->Guid, trans);
|
||||
|
||||
@@ -290,7 +290,7 @@ void WorldSession::HandleGuildBankerActivate(WorldPackets::Guild::GuildBankActiv
|
||||
guild->SendBankTabsInfo(this, packet.FullUpdate);
|
||||
}
|
||||
|
||||
// Called when opening guild bank tab only (first one)
|
||||
// Called when opening guild bank tab only
|
||||
void WorldSession::HandleGuildBankQueryTab(WorldPackets::Guild::GuildBankQueryTab& packet)
|
||||
{
|
||||
LOG_DEBUG("guild", "CMSG_GUILD_BANK_QUERY_TAB [{}]: Go: [{}], TabId: {}, ShowTabs: {}"
|
||||
|
||||
@@ -747,7 +747,8 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
||||
return;
|
||||
}
|
||||
|
||||
bool isTavernAreatrigger = sObjectMgr->IsTavernAreaTrigger(triggerId);
|
||||
uint32 teamFaction = player->GetTeamId(true) == TEAM_ALLIANCE ? FACTION_MASK_ALLIANCE : FACTION_MASK_HORDE;
|
||||
bool isTavernAreatrigger = sObjectMgr->IsTavernAreaTrigger(triggerId, teamFaction);
|
||||
if (!player->IsInAreaTriggerRadius(atEntry, isTavernAreatrigger ? 5.f : 0.f))
|
||||
{
|
||||
LOG_DEBUG("network", "HandleAreaTriggerOpcode: Player {} ({}) too far (trigger map: {} player map: {}), ignore Area Trigger ID: {}",
|
||||
@@ -1702,7 +1703,7 @@ void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recv_data*/)
|
||||
_player->BuildPlayerRepop();
|
||||
_player->ResurrectPlayer(1.0f);
|
||||
_player->SpawnCorpseBones();
|
||||
_player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation());
|
||||
_player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->m_homebindO);
|
||||
}
|
||||
|
||||
void WorldSession::HandleInstanceLockResponse(WorldPacket& recvPacket)
|
||||
|
||||
@@ -92,7 +92,7 @@ void WorldSession::HandleMoveWorldportAck()
|
||||
if (!newMap || newMap->CannotEnter(GetPlayer(), false))
|
||||
{
|
||||
LOG_ERROR("network.opcode", "Map {} could not be created for player {}, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUID().ToString());
|
||||
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
|
||||
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->m_homebindO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ void WorldSession::HandleMoveWorldportAck()
|
||||
GetPlayer()->GetName(), GetPlayer()->GetGUID().ToString(), loc.GetMapId());
|
||||
GetPlayer()->ResetMap();
|
||||
GetPlayer()->SetMap(oldMap);
|
||||
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
|
||||
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->m_homebindO);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ bool LootItemStorage::LoadStoredLoot(Item* item, Player* player)
|
||||
li.randomPropertyId = it2->randomPropertyId;
|
||||
li.randomSuffix = it2->randomSuffix;
|
||||
li.rollWinnerGUID = ObjectGuid::Empty;
|
||||
li.groupid = 0;
|
||||
|
||||
// Copy the extra loot conditions from the item in the loot template
|
||||
lt->CopyConditions(&li, it2->conditionLootId);
|
||||
|
||||
@@ -71,7 +71,7 @@ struct LootGroupInvalidSelector : public Acore::unary_function<LootStoreItem*, b
|
||||
|
||||
uint8 foundDuplicates = 0;
|
||||
for (std::vector<LootItem>::const_iterator itr = _loot.items.begin(); itr != _loot.items.end(); ++itr)
|
||||
if (itr->itemid == item->itemid)
|
||||
if (itr->itemid == item->itemid && itr->groupid == item->groupid)
|
||||
{
|
||||
++foundDuplicates;
|
||||
if (_proto->InventoryType == 0 && foundDuplicates == 3 && _proto->ItemId != 47242 /*Trophy of the Crusade*/) // Non-equippable items are limited to 3 drops
|
||||
@@ -401,6 +401,7 @@ LootItem::LootItem(LootStoreItem const& li)
|
||||
is_underthreshold = 0;
|
||||
is_counted = 0;
|
||||
rollWinnerGUID = ObjectGuid::Empty;
|
||||
groupid = li.groupid;
|
||||
}
|
||||
|
||||
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
|
||||
|
||||
@@ -168,6 +168,7 @@ struct LootItem
|
||||
bool is_counted : 1;
|
||||
bool needs_quest : 1; // quest drop
|
||||
bool follow_loot_rules : 1;
|
||||
uint8 groupid : 7;
|
||||
|
||||
// Constructor, copies most fields from LootStoreItem, generates random count and random suffixes/properties
|
||||
// Should be called for non-reference LootStoreItem entries only (reference = 0)
|
||||
|
||||
@@ -1269,7 +1269,7 @@ void Map::RemoveAllPlayers()
|
||||
{
|
||||
// this is happening for bg
|
||||
LOG_ERROR("maps", "Map::UnloadAll: player {} is still in map {} during unload, this should not happen!", player->GetName(), GetId());
|
||||
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation());
|
||||
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->m_homebindO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "MapUpdater.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "LFGMgr.h"
|
||||
#include "Map.h"
|
||||
#include "MapUpdater.h"
|
||||
#include "Metric.h"
|
||||
|
||||
class UpdateRequest
|
||||
@@ -140,6 +141,10 @@ void MapUpdater::update_finished()
|
||||
|
||||
void MapUpdater::WorkerThread()
|
||||
{
|
||||
LoginDatabase.WarnAboutSyncQueries(true);
|
||||
CharacterDatabase.WarnAboutSyncQueries(true);
|
||||
WorldDatabase.WarnAboutSyncQueries(true);
|
||||
|
||||
while (1)
|
||||
{
|
||||
UpdateRequest* request = nullptr;
|
||||
|
||||
@@ -1146,6 +1146,8 @@ enum AcoreStrings
|
||||
|
||||
LANG_CMD_GOQUEST_INVALID_SYNTAX = 5082,
|
||||
|
||||
LANG_CMD_CHAR_CHANGE_ACC_SUCCESS = 5083,
|
||||
|
||||
// Room for more strings 5083-9999
|
||||
|
||||
// Level requirement notifications
|
||||
|
||||
@@ -93,7 +93,7 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
||||
{
|
||||
if (Creature* cOwner2 = owner->ToCreature())
|
||||
{
|
||||
cOwner2->SetCannotReachTarget(i_path && i_path->GetPathType() & PATHFIND_INCOMPLETE ? target->GetGUID() : ObjectGuid::Empty);
|
||||
cOwner2->SetCannotReachTarget();
|
||||
}
|
||||
|
||||
i_recalculateTravel = false;
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Movement
|
||||
|
||||
void MoveSpline::computeFallElevation(float& el) const
|
||||
{
|
||||
float z_now = spline.getPoint(spline.first(), false).z - Movement::computeFallElevation(MSToSec(time_passed), false);
|
||||
float z_now = spline.getPoint(spline.first()).z - Movement::computeFallElevation(MSToSec(time_passed), false);
|
||||
float final_z = FinalDestination().z;
|
||||
el = std::max(z_now, final_z);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ namespace Movement
|
||||
float start_elevation;
|
||||
inline int32 operator()(Spline<int32>& s, int32 i)
|
||||
{
|
||||
return Movement::computeFallTime(start_elevation - s.getPoint(i + 1, false).z, false) * 1000.f;
|
||||
return Movement::computeFallTime(start_elevation - s.getPoint(i + 1).z, false) * 1000.f;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace Movement
|
||||
// init spline timestamps
|
||||
if (splineflags.falling)
|
||||
{
|
||||
FallInitializer init(spline.getPoint(spline.first(), false).z);
|
||||
FallInitializer init(spline.getPoint(spline.first()).z);
|
||||
spline.initLengths(init);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Movement
|
||||
void init_spline(const MoveSplineInitArgs& args);
|
||||
|
||||
protected:
|
||||
[[nodiscard]] const MySpline::ControlArray& getPath(bool visual) const { return spline.getPoints(visual); }
|
||||
[[nodiscard]] const MySpline::ControlArray& getPath() const { return spline.getPoints(); }
|
||||
void computeParabolicElevation(float& el) const;
|
||||
void computeFallElevation(float& el) const;
|
||||
|
||||
@@ -117,8 +117,8 @@ namespace Movement
|
||||
[[nodiscard]] bool isCyclic() const { return splineflags.cyclic; }
|
||||
[[nodiscard]] bool isFalling() const { return splineflags.falling; }
|
||||
[[nodiscard]] bool isWalking() const { return splineflags.walkmode; }
|
||||
[[nodiscard]] Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last(), false) : Vector3(); }
|
||||
[[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1, false) : Vector3(); }
|
||||
[[nodiscard]] Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last()) : Vector3(); }
|
||||
[[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1) : Vector3(); }
|
||||
[[nodiscard]] int32 currentPathIdx() const;
|
||||
|
||||
[[nodiscard]] bool HasAnimation() const { return splineflags.animation; }
|
||||
|
||||
@@ -135,11 +135,6 @@ namespace Movement
|
||||
data << int8(unit->GetTransSeat());
|
||||
}
|
||||
|
||||
Movement::SplineBase::ControlArray* visualPoints = const_cast<Movement::SplineBase::ControlArray*>(move_spline._Spline().allocateVisualPoints());
|
||||
visualPoints->resize(move_spline._Spline().getPointCount());
|
||||
// Xinef: Apply hover in creature movement packet
|
||||
std::copy(move_spline._Spline().getPoints(false).begin(), move_spline._Spline().getPoints(false).end(), visualPoints->begin());
|
||||
|
||||
PacketBuilder::WriteMonsterMove(move_spline, data);
|
||||
unit->SendMessageToSet(&data, true);
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Movement
|
||||
MoveSplineFlag splineflags = move_spline.splineflags;
|
||||
|
||||
data << uint8(0); // sets/unsets MOVEMENTFLAG2_UNK7 (0x40)
|
||||
data << move_spline.spline.getPoint(move_spline.spline.first(), true);
|
||||
data << move_spline.spline.getPoint(move_spline.spline.first());
|
||||
data << move_spline.GetId();
|
||||
|
||||
switch (splineflags & MoveSplineFlag::Mask_Final_Facing)
|
||||
@@ -99,7 +99,7 @@ namespace Movement
|
||||
void WriteLinearPath(const Spline<int32>& spline, ByteBuffer& data)
|
||||
{
|
||||
uint32 last_idx = spline.getPointCount() - 3;
|
||||
const Vector3* real_path = &spline.getPoint(1, true);
|
||||
const Vector3* real_path = &spline.getPoint(1);
|
||||
|
||||
data << last_idx;
|
||||
data << real_path[last_idx]; // destination
|
||||
@@ -120,7 +120,7 @@ namespace Movement
|
||||
{
|
||||
uint32 count = spline.getPointCount() - 3;
|
||||
data << count;
|
||||
data.append<Vector3>(&spline.getPoint(2, true), count);
|
||||
data.append<Vector3>(&spline.getPoint(2), count);
|
||||
}
|
||||
|
||||
void WriteCatmullRomCyclicPath(const Spline<int32>& spline, ByteBuffer& data, bool flying)
|
||||
@@ -129,12 +129,12 @@ namespace Movement
|
||||
data << uint32(count + 1);
|
||||
if (flying)
|
||||
{
|
||||
data << spline.getPoint(1, true); // fake point, client will erase it from the spline after first cycle done
|
||||
data.append<Vector3>(&spline.getPoint(2, true), count);
|
||||
data << spline.getPoint(1); // fake point, client will erase it from the spline after first cycle done
|
||||
data.append<Vector3>(&spline.getPoint(2), count);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.append<Vector3>(&spline.getPoint(2, true), count);
|
||||
data.append<Vector3>(&spline.getPoint(2), count);
|
||||
data << Vector3::zero(); //Xinef: fake point
|
||||
}
|
||||
}
|
||||
@@ -189,9 +189,9 @@ namespace Movement
|
||||
data << move_spline.vertical_acceleration; // added in 3.1
|
||||
data << move_spline.effect_start_time; // added in 3.1
|
||||
|
||||
uint32 nodes = move_spline.getPath(true).size();
|
||||
uint32 nodes = move_spline.getPath().size();
|
||||
data << nodes;
|
||||
data.append<Vector3>(&move_spline.getPath(true)[0], nodes);
|
||||
data.append<Vector3>(&move_spline.getPath()[0], nodes);
|
||||
data << uint8(move_spline.spline.mode()); // added in 3.1
|
||||
data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination());
|
||||
}
|
||||
|
||||
@@ -286,7 +286,6 @@ namespace Movement
|
||||
index_lo = 0;
|
||||
index_hi = 0;
|
||||
points.clear();
|
||||
pointsVisual.clear();
|
||||
}
|
||||
|
||||
std::string SplineBase::ToString() const
|
||||
|
||||
@@ -42,7 +42,6 @@ namespace Movement
|
||||
|
||||
protected:
|
||||
ControlArray points;
|
||||
ControlArray pointsVisual;
|
||||
|
||||
index_type index_lo{0};
|
||||
index_type index_hi{0};
|
||||
@@ -112,10 +111,9 @@ namespace Movement
|
||||
[[nodiscard]] bool isCyclic() const { return cyclic;}
|
||||
|
||||
// Xinef: DO NOT USE EXCEPT FOR SPLINE INITIALIZATION!!!!!!
|
||||
[[nodiscard]] const ControlArray* allocateVisualPoints() const { return &pointsVisual; }
|
||||
[[nodiscard]] const ControlArray& getPoints(bool visual) const { return visual ? pointsVisual : points;}
|
||||
[[nodiscard]] const ControlArray& getPoints() const { return points;}
|
||||
[[nodiscard]] index_type getPointCount() const { return points.size();}
|
||||
[[nodiscard]] const Vector3& getPoint(index_type i, bool visual) const { return visual ? pointsVisual[i] : points[i];}
|
||||
[[nodiscard]] const Vector3& getPoint(index_type i) const { return points[i];}
|
||||
|
||||
/** Initializes spline. Don't call other methods while spline not initialized. */
|
||||
void init_spline(const Vector3* controls, index_type count, EvaluationMode m);
|
||||
|
||||
@@ -131,6 +131,16 @@ Quest::Quest(Field* questRecord)
|
||||
}
|
||||
|
||||
_eventIdForQuest = 0;
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT))
|
||||
{
|
||||
Flags &= ~QUEST_FLAGS_AUTO_ACCEPT;
|
||||
}
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE))
|
||||
{
|
||||
Flags &= ~QUEST_FLAGS_AUTOCOMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
void Quest::LoadQuestDetails(Field* fields)
|
||||
@@ -180,8 +190,10 @@ void Quest::LoadQuestTemplateAddon(Field* fields)
|
||||
RewardMailSenderEntry = fields[16].Get<uint32>();
|
||||
SpecialFlags = fields[17].Get<uint8>();
|
||||
|
||||
if (SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT)
|
||||
if ((SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) && !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT))
|
||||
{
|
||||
Flags |= QUEST_FLAGS_AUTO_ACCEPT;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Quest::XPValue(uint8 playerLevel) const
|
||||
@@ -253,12 +265,12 @@ uint32 Quest::GetRewMoneyMaxLevel() const
|
||||
|
||||
bool Quest::IsAutoAccept() const
|
||||
{
|
||||
return sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT) ? false : (Flags & QUEST_FLAGS_AUTO_ACCEPT);
|
||||
return HasFlag(QUEST_FLAGS_AUTO_ACCEPT);
|
||||
}
|
||||
|
||||
bool Quest::IsAutoComplete() const
|
||||
{
|
||||
return sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) ? false : HasFlag(QUEST_FLAGS_AUTOCOMPLETE);
|
||||
return HasFlag(QUEST_FLAGS_AUTOCOMPLETE);
|
||||
}
|
||||
|
||||
bool Quest::IsRaidQuest(Difficulty difficulty) const
|
||||
|
||||
@@ -590,6 +590,14 @@ void ScriptMgr::OnLootItem(Player* player, Item* item, uint32 count, ObjectGuid
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::OnStoreNewItem(Player* player, Item* item, uint32 count)
|
||||
{
|
||||
ExecuteScript<PlayerScript>([&](PlayerScript* script)
|
||||
{
|
||||
script->OnStoreNewItem(player, item, count);
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::OnCreateItem(Player* player, Item* item, uint32 count)
|
||||
{
|
||||
ExecuteScript<PlayerScript>([&](PlayerScript* script)
|
||||
|
||||
@@ -69,19 +69,19 @@ void ScriptMgr::ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage)
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage)
|
||||
void ScriptMgr::ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage, SpellInfo const* spellInfo)
|
||||
{
|
||||
ExecuteScript<UnitScript>([&](UnitScript* script)
|
||||
{
|
||||
script->ModifySpellDamageTaken(target, attacker, damage);
|
||||
script->ModifySpellDamageTaken(target, attacker, damage, spellInfo);
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::ModifyHealRecieved(Unit* target, Unit* attacker, uint32& damage)
|
||||
void ScriptMgr::ModifyHealReceived(Unit* target, Unit* healer, uint32& heal, SpellInfo const* spellInfo)
|
||||
{
|
||||
ExecuteScript<UnitScript>([&](UnitScript* script)
|
||||
{
|
||||
script->ModifyHealRecieved(target, attacker, damage);
|
||||
script->ModifyHealReceived(target, healer, heal, spellInfo);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -242,3 +242,11 @@ void ScriptMgr::OnUnitDeath(Unit* unit, Unit* killer)
|
||||
script->OnUnitDeath(unit, killer);
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::OnAuraApply(Unit* unit, Aura* aura)
|
||||
{
|
||||
ExecuteScript<UnitScript>([&](UnitScript* script)
|
||||
{
|
||||
script->OnAuraApply(unit, aura);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -429,16 +429,18 @@ public:
|
||||
virtual void ModifyMeleeDamage(Unit* /*target*/, Unit* /*attacker*/, uint32& /*damage*/) { }
|
||||
|
||||
// Called when Spell Damage is being Dealt
|
||||
virtual void ModifySpellDamageTaken(Unit* /*target*/, Unit* /*attacker*/, int32& /*damage*/) { }
|
||||
virtual void ModifySpellDamageTaken(Unit* /*target*/, Unit* /*attacker*/, int32& /*damage*/, SpellInfo const* /*spellInfo*/) { }
|
||||
|
||||
// Called when Heal is Recieved
|
||||
virtual void ModifyHealRecieved(Unit* /*target*/, Unit* /*attacker*/, uint32& /*damage*/) { }
|
||||
virtual void ModifyHealReceived(Unit* /*target*/, Unit* /*healer*/, uint32& /*heal*/, SpellInfo const* /*spellInfo*/) { }
|
||||
|
||||
//Called when Damage is Dealt
|
||||
virtual uint32 DealDamage(Unit* /*AttackerUnit*/, Unit* /*pVictim*/, uint32 damage, DamageEffectType /*damagetype*/) { return damage; }
|
||||
|
||||
virtual void OnBeforeRollMeleeOutcomeAgainst(Unit const* /*attacker*/, Unit const* /*victim*/, WeaponAttackType /*attType*/, int32& /*attackerMaxSkillValueForLevel*/, int32& /*victimMaxSkillValueForLevel*/, int32& /*attackerWeaponSkill*/, int32& /*victimDefenseSkill*/, int32& /*crit_chance*/, int32& /*miss_chance*/, int32& /*dodge_chance*/, int32& /*parry_chance*/, int32& /*block_chance*/ ) { };
|
||||
|
||||
virtual void OnAuraApply(Unit* /*unit*/, Aura* /*aura*/) { }
|
||||
|
||||
virtual void OnAuraRemove(Unit* /*unit*/, AuraApplication* /*aurApp*/, AuraRemoveMode /*mode*/) { }
|
||||
|
||||
[[nodiscard]] virtual bool IfNormalReaction(Unit const* /*unit*/, Unit const* /*target*/, ReputationRank& /*repRank*/) { return true; }
|
||||
@@ -1180,6 +1182,9 @@ public:
|
||||
//After looting item
|
||||
virtual void OnLootItem(Player* /*player*/, Item* /*item*/, uint32 /*count*/, ObjectGuid /*lootguid*/) { }
|
||||
|
||||
//After looting item (includes master loot).
|
||||
virtual void OnStoreNewItem(Player* /*player*/, Item* /*item*/, uint32 /*count*/) { }
|
||||
|
||||
//After creating item (eg profession item creation)
|
||||
virtual void OnCreateItem(Player* /*player*/, Item* /*item*/, uint32 /*count*/) { }
|
||||
|
||||
@@ -2314,6 +2319,7 @@ public: /* PlayerScript */
|
||||
void GetCustomArenaPersonalRating(Player const* player, uint8 slot, uint32& rating) const;
|
||||
void OnGetMaxPersonalArenaRatingRequirement(Player const* player, uint32 minSlot, uint32& maxArenaRating) const;
|
||||
void OnLootItem(Player* player, Item* item, uint32 count, ObjectGuid lootguid);
|
||||
void OnStoreNewItem(Player* player, Item* item, uint32 count);
|
||||
void OnCreateItem(Player* player, Item* item, uint32 count);
|
||||
void OnQuestRewardItem(Player* player, Item* item, uint32 count);
|
||||
void OnGroupRollRewardItem(Player* player, Item* item, uint32 count, RollVote voteType, Roll* roll);
|
||||
@@ -2471,10 +2477,11 @@ public: /* UnitScript */
|
||||
void OnDamage(Unit* attacker, Unit* victim, uint32& damage);
|
||||
void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage);
|
||||
void ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage);
|
||||
void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage);
|
||||
void ModifyHealRecieved(Unit* target, Unit* attacker, uint32& addHealth);
|
||||
void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage, SpellInfo const* spellInfo);
|
||||
void ModifyHealReceived(Unit* target, Unit* healer, uint32& addHealth, SpellInfo const* spellInfo);
|
||||
uint32 DealDamage(Unit* AttackerUnit, Unit* pVictim, uint32 damage, DamageEffectType damagetype);
|
||||
void OnBeforeRollMeleeOutcomeAgainst(Unit const* attacker, Unit const* victim, WeaponAttackType attType, int32& attackerMaxSkillValueForLevel, int32& victimMaxSkillValueForLevel, int32& attackerWeaponSkill, int32& victimDefenseSkill, int32& crit_chance, int32& miss_chance, int32& dodge_chance, int32& parry_chance, int32& block_chance);
|
||||
void OnAuraApply(Unit* /*unit*/, Aura* /*aura*/);
|
||||
void OnAuraRemove(Unit* unit, AuraApplication* aurApp, AuraRemoveMode mode);
|
||||
bool IfNormalReaction(Unit const* unit, Unit const* target, ReputationRank& repRank);
|
||||
bool IsNeedModSpellDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
|
||||
|
||||
@@ -6619,6 +6619,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
|
||||
|
||||
// Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
|
||||
sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, heal);
|
||||
sScriptMgr->ModifyHealReceived(target, caster, heal, GetSpellInfo());
|
||||
|
||||
HealInfo healInfo(caster, target, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
|
||||
Unit::CalcHealAbsorb(healInfo);
|
||||
|
||||
@@ -976,7 +976,7 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const
|
||||
{
|
||||
uint32 maxProcCharges = m_spellInfo->ProcCharges;
|
||||
if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId()))
|
||||
maxProcCharges = procEntry->charges;
|
||||
maxProcCharges = procEntry->Charges;
|
||||
|
||||
if (caster)
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
@@ -2202,9 +2202,9 @@ bool Aura::IsProcOnCooldown() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void Aura::AddProcCooldown(uint32 /*msec*/)
|
||||
void Aura::AddProcCooldown(Milliseconds /*msec*/)
|
||||
{
|
||||
//m_procCooldown = GameTime::GetGameTime().count() + msec;
|
||||
//m_procCooldown = std:chrono::steady_clock::now() + msec;
|
||||
}
|
||||
|
||||
void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo)
|
||||
@@ -2225,7 +2225,7 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf
|
||||
ASSERT(procEntry);
|
||||
|
||||
// cooldowns should be added to the whole aura (see 51698 area aura)
|
||||
AddProcCooldown(procEntry->cooldown);
|
||||
AddProcCooldown(procEntry->Cooldown);
|
||||
}
|
||||
|
||||
bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const
|
||||
@@ -2314,16 +2314,16 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
|
||||
|
||||
float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
|
||||
{
|
||||
float chance = procEntry.chance;
|
||||
float chance = procEntry.Chance;
|
||||
// calculate chances depending on unit with caster's data
|
||||
// so talents modifying chances and judgements will have properly calculated proc chance
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
// calculate ppm chance if present and we're using weapon
|
||||
if (eventInfo.GetDamageInfo() && procEntry.ratePerMinute != 0)
|
||||
if (eventInfo.GetDamageInfo() && procEntry.ProcsPerMinute != 0)
|
||||
{
|
||||
uint32 WeaponSpeed = caster->GetAttackTime(eventInfo.GetDamageInfo()->GetAttackType());
|
||||
chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ratePerMinute, GetSpellInfo());
|
||||
chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ProcsPerMinute, GetSpellInfo());
|
||||
}
|
||||
// apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell)
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
@@ -2923,15 +2923,20 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
|
||||
|
||||
for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
|
||||
{
|
||||
// xinef: check z level and los dependence
|
||||
Unit* target = *itr;
|
||||
float zLevel = GetDynobjOwner()->GetPositionZ();
|
||||
if (target->GetPositionZ() + 3.0f < zLevel || target->GetPositionZ() - 5.0f > zLevel)
|
||||
|
||||
Optional<float> collisionHeight = { };
|
||||
Optional<float> combatReach = { };
|
||||
if (Unit* dynObjCaster = GetDynobjOwner()->GetCaster())
|
||||
{
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !target->IsWithinLOSInMap(GetDynobjOwner()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
collisionHeight = dynObjCaster->GetCollisionHeight();
|
||||
combatReach = dynObjCaster->GetCombatReach();
|
||||
}
|
||||
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) &&
|
||||
!GetDynobjOwner()->IsWithinLOSInMap(target, VMAP::ModelIgnoreFlags::Nothing, LINEOFSIGHT_ALL_CHECKS, collisionHeight, combatReach))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<Unit*, uint8>::iterator existing = targets.find(*itr);
|
||||
|
||||
@@ -196,7 +196,7 @@ public:
|
||||
// and some dependant problems fixed before it can replace old proc system (for example cooldown handling)
|
||||
// currently proc system functionality is implemented in Unit::ProcDamageAndSpell
|
||||
bool IsProcOnCooldown() const;
|
||||
void AddProcCooldown(uint32 msec);
|
||||
void AddProcCooldown(Milliseconds msec);
|
||||
bool IsUsingCharges() const { return m_isUsingCharges; }
|
||||
void SetUsingCharges(bool val) { m_isUsingCharges = val; }
|
||||
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
|
||||
@@ -1344,7 +1344,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
|
||||
break;
|
||||
case TARGET_DEST_HOME:
|
||||
if (Player* playerCaster = m_caster->ToPlayer())
|
||||
dest = SpellDestination(playerCaster->m_homebindX, playerCaster->m_homebindY, playerCaster->m_homebindZ, playerCaster->GetOrientation(), playerCaster->m_homebindMapId);
|
||||
dest = SpellDestination(playerCaster->m_homebindX, playerCaster->m_homebindY, playerCaster->m_homebindZ, playerCaster->m_homebindO, playerCaster->m_homebindMapId);
|
||||
break;
|
||||
case TARGET_DEST_DB:
|
||||
if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, effIndex))
|
||||
@@ -2428,9 +2428,11 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
|
||||
// Calculate hit result
|
||||
if (m_originalCaster)
|
||||
{
|
||||
targetInfo.missCondition = m_originalCaster->SpellHitResult(target, m_spellInfo, m_canReflect);
|
||||
targetInfo.missCondition = m_originalCaster->SpellHitResult(target, this, m_canReflect);
|
||||
if (m_skipCheck && targetInfo.missCondition != SPELL_MISS_IMMUNE)
|
||||
{
|
||||
targetInfo.missCondition = SPELL_MISS_NONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
targetInfo.missCondition = SPELL_MISS_EVADE; //SPELL_MISS_NONE;
|
||||
@@ -2458,7 +2460,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
|
||||
if (targetInfo.missCondition == SPELL_MISS_REFLECT)
|
||||
{
|
||||
// Calculate reflected spell result on caster
|
||||
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect);
|
||||
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, this, m_canReflect);
|
||||
|
||||
if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell
|
||||
targetInfo.reflectResult = SPELL_MISS_PARRY;
|
||||
@@ -2971,8 +2973,10 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
|
||||
return SPELL_MISS_EVADE;
|
||||
|
||||
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
|
||||
if (m_spellInfo->Speed && ((m_damage > 0 && unit->IsImmunedToDamage(m_spellInfo)) || unit->IsImmunedToSchool(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo)))
|
||||
if (m_spellInfo->Speed && ((m_damage > 0 && unit->IsImmunedToDamage(this)) || unit->IsImmunedToSchool(this) || unit->IsImmunedToSpell(m_spellInfo, this)))
|
||||
{
|
||||
return SPELL_MISS_IMMUNE;
|
||||
}
|
||||
|
||||
// disable effects to which unit is immune
|
||||
SpellMissInfo returnVal = SPELL_MISS_IMMUNE;
|
||||
@@ -3970,6 +3974,20 @@ void Spell::_cast(bool skipCheck)
|
||||
if (modOwner)
|
||||
modOwner->SetSpellModTakingSpell(this, true);
|
||||
|
||||
bool resetAttackTimers = IsAutoActionResetSpell() && !m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS);
|
||||
if (resetAttackTimers)
|
||||
{
|
||||
Unit::AuraEffectList const& vIgnoreReset = m_caster->GetAuraEffectsByType(SPELL_AURA_IGNORE_MELEE_RESET);
|
||||
for (Unit::AuraEffectList::const_iterator i = vIgnoreReset.begin(); i != vIgnoreReset.end(); ++i)
|
||||
{
|
||||
if ((*i)->IsAffectedOnSpell(m_spellInfo))
|
||||
{
|
||||
resetAttackTimers = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
|
||||
if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled())/* xinef: we dont need this || m_spellInfo->Id == 14157*/)
|
||||
{
|
||||
@@ -4002,38 +4020,23 @@ void Spell::_cast(bool skipCheck)
|
||||
handle_immediate();
|
||||
}
|
||||
|
||||
if (IsAutoActionResetSpell())
|
||||
if (resetAttackTimers)
|
||||
{
|
||||
bool found = false;
|
||||
Unit::AuraEffectList const& vIgnoreReset = m_caster->GetAuraEffectsByType(SPELL_AURA_IGNORE_MELEE_RESET);
|
||||
for (Unit::AuraEffectList::const_iterator i = vIgnoreReset.begin(); i != vIgnoreReset.end(); ++i)
|
||||
if (m_casttime == 0 && m_spellInfo->CalcCastTime())
|
||||
{
|
||||
if ((*i)->IsAffectedOnSpell(m_spellInfo))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
resetAttackTimers = false;
|
||||
}
|
||||
|
||||
if (!found && !m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS))
|
||||
if (resetAttackTimers)
|
||||
{
|
||||
bool allow = true;
|
||||
if (m_casttime == 0 && m_spellInfo->CalcCastTime())
|
||||
m_caster->resetAttackTimer(BASE_ATTACK);
|
||||
|
||||
if (m_caster->haveOffhandWeapon())
|
||||
{
|
||||
allow = false;
|
||||
m_caster->resetAttackTimer(OFF_ATTACK);
|
||||
}
|
||||
|
||||
if (allow)
|
||||
{
|
||||
m_caster->resetAttackTimer(BASE_ATTACK);
|
||||
|
||||
if (m_caster->haveOffhandWeapon())
|
||||
{
|
||||
m_caster->resetAttackTimer(OFF_ATTACK);
|
||||
}
|
||||
|
||||
m_caster->resetAttackTimer(RANGED_ATTACK);
|
||||
}
|
||||
m_caster->resetAttackTimer(RANGED_ATTACK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -589,6 +589,8 @@ public:
|
||||
|
||||
[[nodiscard]] TriggerCastFlags GetTriggeredCastFlags() const { return _triggeredCastFlags; }
|
||||
|
||||
[[nodiscard]] SpellSchoolMask GetSpellSchoolMask() const { return m_spellSchoolMask; }
|
||||
|
||||
protected:
|
||||
bool HasGlobalCooldown() const;
|
||||
void TriggerGlobalCooldown();
|
||||
|
||||
@@ -319,7 +319,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/)
|
||||
Unit::DealDamageMods(unitTarget, envDamage, &absorb);
|
||||
damage = envDamage;
|
||||
|
||||
m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0, false);
|
||||
m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,8 +593,14 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
|
||||
if (Player* caster = m_caster->ToPlayer())
|
||||
{
|
||||
// Add Ammo and Weapon damage plus RAP * 0.1
|
||||
float dmg_min = caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE);
|
||||
float dmg_max = caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE);
|
||||
float dmg_min = 0.f;
|
||||
float dmg_max = 0.f;
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
|
||||
{
|
||||
dmg_min += caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE, i);
|
||||
dmg_max += caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE, i);
|
||||
}
|
||||
|
||||
if (dmg_max == 0.0f && dmg_min > dmg_max)
|
||||
{
|
||||
damage += int32(dmg_min);
|
||||
@@ -616,9 +622,17 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
|
||||
// Add main hand dps * effect[2] amount
|
||||
if (Player* player = m_caster->ToPlayer())
|
||||
{
|
||||
float mindamage, maxdamage;
|
||||
player->CalculateMinMaxDamage(BASE_ATTACK, false, false, mindamage, maxdamage);
|
||||
float average = (mindamage + maxdamage) / 2;
|
||||
float minTotal = 0.f;
|
||||
float maxTotal = 0.f;
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
|
||||
{
|
||||
float tmpMin, tmpMax;
|
||||
player->CalculateMinMaxDamage(BASE_ATTACK, false, false, tmpMin, tmpMax, i);
|
||||
minTotal += tmpMin;
|
||||
maxTotal += tmpMax;
|
||||
}
|
||||
|
||||
float average = (minTotal + maxTotal) / 2;
|
||||
int32 count = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_2);
|
||||
damage += count * int32(average * IN_MILLISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
|
||||
}
|
||||
@@ -3644,8 +3658,8 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
|
||||
uint32 eff_damage(std::max(weaponDamage, 0));
|
||||
|
||||
// Add melee damage bonuses (also check for negative)
|
||||
eff_damage = m_caster->MeleeDamageBonusDone(unitTarget, eff_damage, m_attackType, m_spellInfo);
|
||||
eff_damage = unitTarget->MeleeDamageBonusTaken(m_caster, eff_damage, m_attackType, m_spellInfo);
|
||||
eff_damage = m_caster->MeleeDamageBonusDone(unitTarget, eff_damage, m_attackType, m_spellInfo, m_spellSchoolMask);
|
||||
eff_damage = unitTarget->MeleeDamageBonusTaken(m_caster, eff_damage, m_attackType, m_spellInfo, m_spellSchoolMask);
|
||||
|
||||
// Meteor like spells (divided damage to targets)
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_SHARE_DAMAGE))
|
||||
@@ -5516,6 +5530,11 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex)
|
||||
|
||||
ExecuteLogEffectSummonObject(effIndex, linkedTrap);
|
||||
}
|
||||
|
||||
if (Player* player = m_caster->ToPlayer())
|
||||
{
|
||||
player->SetCanTeleport(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::EffectProspecting(SpellEffIndex /*effIndex*/)
|
||||
|
||||
@@ -4415,6 +4415,26 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AuraInterruptFlags &= ~AURA_INTERRUPT_FLAG_NOT_ABOVEWATER;
|
||||
});
|
||||
|
||||
// Summon Worm
|
||||
ApplySpellFix({ 518, 25831, 25832 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].MiscValueB = 64;
|
||||
});
|
||||
|
||||
// Uppercut
|
||||
ApplySpellFix({ 26007 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_CASTER_PROCS;
|
||||
});
|
||||
|
||||
// Digestive Acid (Temporary)
|
||||
ApplySpellFix({ 26476 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Attributes |= SPELL_ATTR0_NO_IMMUNITIES;
|
||||
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_ALWAYS_HIT;
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -898,11 +898,11 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
|
||||
bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
|
||||
{
|
||||
// proc type doesn't match
|
||||
if (!(eventInfo.GetTypeMask() & procEntry.typeMask))
|
||||
if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags))
|
||||
return false;
|
||||
|
||||
// check XP or honor target requirement
|
||||
if (procEntry.attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)
|
||||
if (procEntry.AttributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)
|
||||
if (Player* actor = eventInfo.GetActor()->ToPlayer())
|
||||
if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
|
||||
return false;
|
||||
@@ -912,37 +912,37 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE
|
||||
return true;
|
||||
|
||||
// check school mask (if set) for other trigger types
|
||||
if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask))
|
||||
if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask))
|
||||
return false;
|
||||
|
||||
// check spell family name/flags (if set) for spells
|
||||
if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION))
|
||||
{
|
||||
if (procEntry.spellFamilyName && (procEntry.spellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName))
|
||||
if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName))
|
||||
return false;
|
||||
|
||||
if (procEntry.spellFamilyMask && !(procEntry.spellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags))
|
||||
if (procEntry.SpellFamilyMask && !(procEntry.SpellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check spell type mask (if set)
|
||||
if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))
|
||||
{
|
||||
if (procEntry.spellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.spellTypeMask))
|
||||
if (procEntry.SpellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.SpellTypeMask))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check spell phase mask
|
||||
if (eventInfo.GetTypeMask() & REQ_SPELL_PHASE_PROC_FLAG_MASK)
|
||||
{
|
||||
if (!(eventInfo.GetSpellPhaseMask() & procEntry.spellPhaseMask))
|
||||
if (!(eventInfo.GetSpellPhaseMask() & procEntry.SpellPhaseMask))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check hit mask (on taken hit or on done hit, but not on spell cast phase)
|
||||
if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)))
|
||||
{
|
||||
uint32 hitMask = procEntry.hitMask;
|
||||
uint32 hitMask = procEntry.HitMask;
|
||||
// get default values if hit mask not set
|
||||
if (!hitMask)
|
||||
{
|
||||
@@ -1143,7 +1143,7 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
if (!sWorld->getBoolConfig(CONFIG_WINTERGRASP_ENABLE))
|
||||
if (sWorld->getIntConfig(CONFIG_WINTERGRASP_ENABLE) != 1)
|
||||
return false;
|
||||
|
||||
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG);
|
||||
@@ -1833,8 +1833,8 @@ void SpellMgr::LoadSpellProcs()
|
||||
|
||||
mSpellProcMap.clear(); // need for reload case
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
||||
QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc");
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
||||
QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 Spell Proc Conditions And Data. DB table `spell_proc` Is Empty.");
|
||||
@@ -1874,21 +1874,20 @@ void SpellMgr::LoadSpellProcs()
|
||||
|
||||
SpellProcEntry baseProcEntry;
|
||||
|
||||
baseProcEntry.schoolMask = fields[1].Get<int8>();
|
||||
baseProcEntry.spellFamilyName = fields[2].Get<uint16>();
|
||||
baseProcEntry.spellFamilyMask[0] = fields[3].Get<uint32>();
|
||||
baseProcEntry.spellFamilyMask[1] = fields[4].Get<uint32>();
|
||||
baseProcEntry.spellFamilyMask[2] = fields[5].Get<uint32>();
|
||||
baseProcEntry.typeMask = fields[6].Get<uint32>();
|
||||
baseProcEntry.spellTypeMask = fields[7].Get<uint32>();
|
||||
baseProcEntry.spellPhaseMask = fields[8].Get<uint32>();
|
||||
baseProcEntry.hitMask = fields[9].Get<uint32>();
|
||||
baseProcEntry.attributesMask = fields[10].Get<uint32>();
|
||||
baseProcEntry.ratePerMinute = fields[11].Get<float>();
|
||||
baseProcEntry.chance = fields[12].Get<float>();
|
||||
float cooldown = fields[13].Get<float>();
|
||||
baseProcEntry.cooldown = uint32(cooldown);
|
||||
baseProcEntry.charges = fields[14].Get<uint32>();
|
||||
baseProcEntry.SchoolMask = fields[1].Get<int8>();
|
||||
baseProcEntry.SpellFamilyName = fields[2].Get<uint16>();
|
||||
baseProcEntry.SpellFamilyMask[0] = fields[3].Get<uint32>();
|
||||
baseProcEntry.SpellFamilyMask[1] = fields[4].Get<uint32>();
|
||||
baseProcEntry.SpellFamilyMask[2] = fields[5].Get<uint32>();
|
||||
baseProcEntry.ProcFlags = fields[6].Get<uint32>();
|
||||
baseProcEntry.SpellTypeMask = fields[7].Get<uint32>();
|
||||
baseProcEntry.SpellPhaseMask = fields[8].Get<uint32>();
|
||||
baseProcEntry.HitMask = fields[9].Get<uint32>();
|
||||
baseProcEntry.AttributesMask = fields[10].Get<uint32>();
|
||||
baseProcEntry.ProcsPerMinute = fields[11].Get<float>();
|
||||
baseProcEntry.Chance = fields[12].Get<float>();
|
||||
baseProcEntry.Cooldown = Milliseconds(fields[13].Get<uint32>());
|
||||
baseProcEntry.Charges = fields[14].Get<uint32>();
|
||||
|
||||
while (spellInfo)
|
||||
{
|
||||
@@ -1900,56 +1899,51 @@ void SpellMgr::LoadSpellProcs()
|
||||
SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
|
||||
|
||||
// take defaults from dbcs
|
||||
if (!procEntry.typeMask)
|
||||
procEntry.typeMask = spellInfo->ProcFlags;
|
||||
if (!procEntry.charges)
|
||||
procEntry.charges = spellInfo->ProcCharges;
|
||||
if (!procEntry.chance && !procEntry.ratePerMinute)
|
||||
procEntry.chance = float(spellInfo->ProcChance);
|
||||
if (!procEntry.ProcFlags)
|
||||
procEntry.ProcFlags = spellInfo->ProcFlags;
|
||||
if (!procEntry.Charges)
|
||||
procEntry.Charges = spellInfo->ProcCharges;
|
||||
if (!procEntry.Chance && !procEntry.ProcsPerMinute)
|
||||
procEntry.Chance = float(spellInfo->ProcChance);
|
||||
|
||||
// validate data
|
||||
if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `schoolMask` set: {}", spellId, procEntry.schoolMask);
|
||||
if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellFamilyName` set: {}", spellId, procEntry.spellFamilyName);
|
||||
if (procEntry.chance < 0)
|
||||
if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SchoolMask` set: {}", spellId, procEntry.SchoolMask);
|
||||
if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellFamilyName` set: {}", spellId, procEntry.SpellFamilyName);
|
||||
if (procEntry.Chance < 0)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `chance` field", spellId);
|
||||
procEntry.chance = 0;
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `Chance` field", spellId);
|
||||
procEntry.Chance = 0;
|
||||
}
|
||||
if (procEntry.ratePerMinute < 0)
|
||||
if (procEntry.ProcsPerMinute < 0)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `ratePerMinute` field", spellId);
|
||||
procEntry.ratePerMinute = 0;
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `ProcsPerMinute` field", spellId);
|
||||
procEntry.ProcsPerMinute = 0;
|
||||
}
|
||||
if (cooldown < 0)
|
||||
if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellId);
|
||||
if (procEntry.Charges > 99)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `cooldown` field", spellId);
|
||||
procEntry.cooldown = 0;
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has too big value in `Charges` field", spellId);
|
||||
procEntry.Charges = 99;
|
||||
}
|
||||
if (procEntry.chance == 0 && procEntry.ratePerMinute == 0)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellId);
|
||||
if (procEntry.charges > 99)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has too big value in `charges` field", spellId);
|
||||
procEntry.charges = 99;
|
||||
}
|
||||
if (!procEntry.typeMask)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `typeMask` value defined, proc will not be triggered", spellId);
|
||||
if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellTypeMask` set: {}", spellId, procEntry.spellTypeMask);
|
||||
if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellId);
|
||||
if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellId);
|
||||
if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellPhaseMask` set: {}", spellId, procEntry.spellPhaseMask);
|
||||
if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellId);
|
||||
if (procEntry.hitMask & ~PROC_HIT_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `hitMask` set: {}", spellId, procEntry.hitMask);
|
||||
if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellId);
|
||||
if (!procEntry.ProcFlags)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `ProcFlags` value defined, proc will not be triggered", spellId);
|
||||
if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellTypeMask` set: {}", spellId, procEntry.SpellTypeMask);
|
||||
if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellTypeMask` value defined, but it won't be used for defined `ProcFlags` value", spellId);
|
||||
if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `SpellPhaseMask` value defined, but it's required for defined `ProcFlags` value, proc will not be triggered", spellId);
|
||||
if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellPhaseMask` set: {}", spellId, procEntry.SpellPhaseMask);
|
||||
if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellPhaseMask` value defined, but it won't be used for defined `ProcFlags` value", spellId);
|
||||
if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `HitMask` set: {}", spellId, procEntry.HitMask);
|
||||
if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `HitMask` value defined, but it won't be used for defined `ProcFlags` and `SpellPhaseMask` values", spellId);
|
||||
|
||||
mSpellProcMap[spellInfo->Id] = procEntry;
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ enum ProcFlagsHit
|
||||
PROC_HIT_REFLECT = 0x0000800,
|
||||
PROC_HIT_INTERRUPT = 0x0001000, // (not used atm)
|
||||
PROC_HIT_FULL_BLOCK = 0x0002000,
|
||||
PROC_HIT_MASK_ALL = 0x2FFF,
|
||||
PROC_HIT_MASK_ALL = 0x0002FFF,
|
||||
};
|
||||
|
||||
enum ProcAttributes
|
||||
@@ -288,18 +288,18 @@ typedef std::unordered_map<uint32, SpellProcEventEntry> SpellProcEventMap;
|
||||
|
||||
struct SpellProcEntry
|
||||
{
|
||||
uint32 schoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
|
||||
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName
|
||||
flag96 spellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags
|
||||
uint32 typeMask; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags
|
||||
uint32 spellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType
|
||||
uint32 spellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase
|
||||
uint32 hitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit
|
||||
uint32 attributesMask; // bitmask, see ProcAttributes
|
||||
float ratePerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60
|
||||
float chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set
|
||||
uint32 cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura
|
||||
uint32 charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite
|
||||
uint32 SchoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
|
||||
uint32 SpellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName
|
||||
flag96 SpellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags
|
||||
uint32 ProcFlags; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags
|
||||
uint32 SpellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType
|
||||
uint32 SpellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase
|
||||
uint32 HitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit
|
||||
uint32 AttributesMask; // bitmask, see ProcAttributes
|
||||
float ProcsPerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60
|
||||
float Chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if ProcsPerMinute set
|
||||
Milliseconds Cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura
|
||||
uint32 Charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32, SpellProcEntry> SpellProcMap;
|
||||
|
||||
@@ -139,7 +139,6 @@ enum WorldBoolConfigs
|
||||
CONFIG_ALLOW_TICKETS,
|
||||
CONFIG_DELETE_CHARACTER_TICKET_TRACE,
|
||||
CONFIG_PRESERVE_CUSTOM_CHANNELS,
|
||||
CONFIG_WINTERGRASP_ENABLE,
|
||||
CONFIG_PDUMP_NO_PATHS,
|
||||
CONFIG_PDUMP_NO_OVERWRITE,
|
||||
CONFIG_ENABLE_MMAPS, // pussywizard
|
||||
@@ -312,6 +311,7 @@ enum WorldIntConfigs
|
||||
CONFIG_BATTLEGROUND_SPEED_BUFF_RESPAWN,
|
||||
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_LIMIT_MIN_LEVEL,
|
||||
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_LIMIT_MIN_PLAYERS,
|
||||
CONFIG_WINTERGRASP_ENABLE,
|
||||
CONFIG_ARENA_MAX_RATING_DIFFERENCE,
|
||||
CONFIG_ARENA_RATING_DISCARD_TIMER,
|
||||
CONFIG_ARENA_PREV_OPPONENTS_DISCARD_TIMER,
|
||||
|
||||
@@ -1385,7 +1385,7 @@ void World::LoadConfigSettings(bool reload)
|
||||
MMAP::MMapFactory::InitializeDisabledMaps();
|
||||
|
||||
// Wintergrasp
|
||||
m_bool_configs[CONFIG_WINTERGRASP_ENABLE] = sConfigMgr->GetOption<bool>("Wintergrasp.Enable", false);
|
||||
m_int_configs[CONFIG_WINTERGRASP_ENABLE] = sConfigMgr->GetOption<int32>("Wintergrasp.Enable", 1);
|
||||
m_int_configs[CONFIG_WINTERGRASP_PLR_MAX] = sConfigMgr->GetOption<int32>("Wintergrasp.PlayerMax", 100);
|
||||
m_int_configs[CONFIG_WINTERGRASP_PLR_MIN] = sConfigMgr->GetOption<int32>("Wintergrasp.PlayerMin", 0);
|
||||
m_int_configs[CONFIG_WINTERGRASP_PLR_MIN_LVL] = sConfigMgr->GetOption<int32>("Wintergrasp.PlayerMinLvl", 77);
|
||||
|
||||
Reference in New Issue
Block a user