Merge branch 'master' into Playerbot

# Conflicts:
#	src/server/game/Guilds/Guild.cpp
This commit is contained in:
郑佩茹
2022-11-18 10:21:36 -07:00
312 changed files with 104564 additions and 1583 deletions
@@ -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;
+13 -9
View File
@@ -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
+3 -3
View File
@@ -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; }
+7 -11
View File
@@ -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();
+3 -3
View File
@@ -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;
+9 -2
View File
@@ -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);
+117 -79
View File
@@ -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);
}
+5 -2
View File
@@ -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))
{
+40 -11
View File
@@ -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
+45 -23
View File
@@ -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);
}
+2
View File
@@ -106,6 +106,8 @@ namespace ObjectAccessor
template<>
void RemoveObject(Player* player);
void UpdatePlayerNameMapReference(std::string oldname, Player* player);
}
#endif
+4 -2
View File
@@ -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));
+9 -3
View File
@@ -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;
+19 -6
View File
@@ -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;
+10 -3
View File
@@ -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);
+1 -1
View File
@@ -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: {}"
+3 -2
View File
@@ -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)
+2 -2
View File
@@ -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;
}
+1
View File
@@ -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);
+2 -1
View File
@@ -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
+1
View File
@@ -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)
+1 -1
View File
@@ -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);
}
}
}
+6 -1
View File
@@ -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;
+2
View File
@@ -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
+3 -3
View File
@@ -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
+2 -4
View File
@@ -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);
+15 -3
View File
@@ -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);
});
}
+11 -4
View File
@@ -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);
+19 -14
View File
@@ -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);
+1 -1
View File
@@ -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);
+31 -28
View File
@@ -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);
}
}
+2
View File
@@ -589,6 +589,8 @@ public:
[[nodiscard]] TriggerCastFlags GetTriggeredCastFlags() const { return _triggeredCastFlags; }
[[nodiscard]] SpellSchoolMask GetSpellSchoolMask() const { return m_spellSchoolMask; }
protected:
bool HasGlobalCooldown() const;
void TriggerGlobalCooldown();
+27 -8
View File
@@ -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];
+62 -68
View File
@@ -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;
+13 -13
View File
@@ -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;
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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);