Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
@@ -195,13 +195,14 @@ void AuthSession::CheckIpCallback(PreparedQueryResult result)
|
||||
{
|
||||
bool banned = false;
|
||||
|
||||
do
|
||||
for (auto const& fields : *result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
if (fields[0].Get<uint64>() != 0)
|
||||
{
|
||||
banned = true;
|
||||
|
||||
} while (result->NextRow());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (banned)
|
||||
{
|
||||
|
||||
@@ -95,7 +95,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_SEL_MAIL_SERVER_CHARACTER, "SELECT mailId from mail_server_character WHERE guid = ? and mailId = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_REP_MAIL_SERVER_CHARACTER, "REPLACE INTO mail_server_character (guid, mailId) values (?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_SOCIALLIST, "SELECT friend, flags, note FROM character_social JOIN characters ON characters.guid = character_social.friend WHERE character_social.guid = ? AND deleteinfos_name IS NULL LIMIT 255", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ, posO FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, category, item, time, needSend FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = ?", CONNECTION_ASYNC);
|
||||
@@ -290,8 +290,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_DEL_PLAYER_ENTRY_POINT, "DELETE FROM character_entry_point WHERE guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
// Character homebind
|
||||
PrepareStatement(CHAR_INS_PLAYER_HOMEBIND, "INSERT INTO character_homebind (guid, mapId, zoneId, posX, posY, posZ) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_PLAYER_HOMEBIND, "UPDATE character_homebind SET mapId = ?, zoneId = ?, posX = ?, posY = ?, posZ = ? WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_PLAYER_HOMEBIND, "INSERT INTO character_homebind (guid, mapId, zoneId, posX, posY, posZ, posO) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_PLAYER_HOMEBIND, "UPDATE character_homebind SET mapId = ?, zoneId = ?, posX = ?, posY = ?, posZ = ?, posO = ? WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_PLAYER_HOMEBIND, "DELETE FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
// Corpse
|
||||
@@ -407,7 +407,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM character_banned WHERE guid = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_PINFO_MAILS, "SELECT SUM(CASE WHEN (checked & 1) THEN 1 ELSE 0 END) AS 'readmail', COUNT(*) AS 'totalmail' FROM mail WHERE `receiver` = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_PINFO_XP, "SELECT a.xp, b.guid FROM characters a LEFT JOIN guild_member b ON a.guid = b.guid WHERE a.guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ, posO FROM character_homebind WHERE guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_GUID_NAME_BY_ACC, "SELECT guid, name FROM characters WHERE account = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_POOL_QUEST_SAVE, "SELECT quest_id FROM pool_quest_save WHERE pool_id = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_AT_LOGIN, "SELECT at_login FROM characters WHERE guid = ?", CONNECTION_SYNCH);
|
||||
|
||||
@@ -24,6 +24,27 @@
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
template<typename T>
|
||||
struct ResultIterator
|
||||
{
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = T;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
|
||||
explicit ResultIterator(pointer ptr) : _ptr(ptr) { }
|
||||
|
||||
reference operator*() const { return *_ptr; }
|
||||
pointer operator->() { return _ptr; }
|
||||
ResultIterator& operator++() { if (!_ptr->NextRow()) _ptr = nullptr; return *this; }
|
||||
|
||||
bool operator!=(const ResultIterator& right) { return _ptr != right._ptr; }
|
||||
|
||||
private:
|
||||
pointer _ptr;
|
||||
};
|
||||
|
||||
class AC_DATABASE_API ResultSet
|
||||
{
|
||||
public:
|
||||
@@ -54,6 +75,9 @@ public:
|
||||
return theTuple;
|
||||
}
|
||||
|
||||
auto begin() { return ResultIterator<ResultSet>(this); }
|
||||
static auto end() { return ResultIterator<ResultSet>(nullptr); }
|
||||
|
||||
protected:
|
||||
std::vector<QueryResultFieldMetadata> _fieldMetadata;
|
||||
uint64 _rowCount;
|
||||
@@ -100,6 +124,9 @@ public:
|
||||
return theTuple;
|
||||
}
|
||||
|
||||
auto begin() { return ResultIterator<PreparedResultSet>(this); }
|
||||
static auto end() { return ResultIterator<PreparedResultSet>(nullptr); }
|
||||
|
||||
protected:
|
||||
std::vector<QueryResultFieldMetadata> m_fieldMetadata;
|
||||
std::vector<Field> m_rows;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace lfg
|
||||
sLFGMgr->LeaveLfg(player->GetGUID());
|
||||
sLFGMgr->LeaveAllLfgQueues(player->GetGUID(), true);
|
||||
player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW);
|
||||
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, 0.0f);
|
||||
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->m_homebindO);
|
||||
LOG_DEBUG("lfg", "LFGPlayerScript::OnMapChanged, Player {} ({}) is in LFG dungeon map but does not have a valid group! Teleporting to homebind.",
|
||||
player->GetName(), player->GetGUID().ToString());
|
||||
return;
|
||||
|
||||
@@ -646,7 +646,7 @@ void Creature::Update(uint32 diff)
|
||||
if (!allowed) // Will be rechecked on next Update call
|
||||
break;
|
||||
|
||||
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(GetEntry(), m_spawnId);
|
||||
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(m_creatureData ? m_creatureData->id1 : GetEntry(), m_spawnId);
|
||||
time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid);
|
||||
if (!linkedRespawntime) // Can respawn
|
||||
Respawn();
|
||||
@@ -2157,7 +2157,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 +2179,7 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo)
|
||||
if (immunedToAllEffects)
|
||||
return true;
|
||||
|
||||
return Unit::IsImmunedToSpell(spellInfo);
|
||||
return Unit::IsImmunedToSpell(spellInfo, spell);
|
||||
}
|
||||
|
||||
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const
|
||||
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
[[nodiscard]] bool IsValidTrainerForPlayer(Player* player, uint32* npcFlags = nullptr) const;
|
||||
bool CanCreatureAttack(Unit const* victim, bool skipDistCheck = false) const;
|
||||
void LoadSpellTemplateImmunity();
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo) override;
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell = nullptr) override;
|
||||
|
||||
[[nodiscard]] bool HasMechanicTemplateImmunity(uint32 mask) const;
|
||||
// redefine Unit::IsImmunedToSpell
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
return (getLevel() / 2 + uint32(GetStat(STAT_STRENGTH) / 20));
|
||||
}
|
||||
|
||||
[[nodiscard]] SpellSchoolMask GetMeleeDamageSchoolMask() const override { return m_meleeDamageSchoolMask; }
|
||||
[[nodiscard]] SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType /*attackType*/ = BASE_ATTACK, uint8 /*damageIndex*/ = 0) const override { return m_meleeDamageSchoolMask; }
|
||||
void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }
|
||||
|
||||
void _AddCreatureSpellCooldown(uint32 spell_id, uint16 categoryId, uint32 end_time);
|
||||
@@ -178,7 +178,7 @@ public:
|
||||
void UpdateMaxHealth() override;
|
||||
void UpdateMaxPower(Powers power) override;
|
||||
void UpdateAttackPowerAndDamage(bool ranged = false) override;
|
||||
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override;
|
||||
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
|
||||
|
||||
void SetCanDualWield(bool value) override;
|
||||
[[nodiscard]] int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -11284,7 +11296,7 @@ void Player::SendInitialPacketsBeforeAddToMap()
|
||||
|
||||
// Homebind
|
||||
WorldPacket data(SMSG_BINDPOINTUPDATE, 5 * 4);
|
||||
data << m_homebindX << m_homebindY << m_homebindZ;
|
||||
data << m_homebindX << m_homebindY << m_homebindZ << m_homebindO;
|
||||
data << (uint32) m_homebindMapId;
|
||||
data << (uint32) m_homebindAreaId;
|
||||
GetSession()->SendPacket(&data);
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -4922,7 +4922,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 +4930,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 +5105,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();
|
||||
|
||||
@@ -7004,7 +7005,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 +7015,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 +7038,20 @@ bool Player::_LoadHomeBind(PreparedQueryResult result)
|
||||
m_homebindX = info->positionX;
|
||||
m_homebindY = info->positionY;
|
||||
m_homebindZ = info->positionZ;
|
||||
|
||||
m_homebindO = info->orientation;
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND);
|
||||
stmt->SetData(0, GetGUID().GetCounter());
|
||||
stmt->SetData(1, m_homebindMapId);
|
||||
stmt->SetData(2, m_homebindAreaId);
|
||||
stmt->SetData (3, m_homebindX);
|
||||
stmt->SetData (4, m_homebindY);
|
||||
stmt->SetData (5, m_homebindZ);
|
||||
stmt->SetData(3, m_homebindX);
|
||||
stmt->SetData(4, m_homebindY);
|
||||
stmt->SetData(5, m_homebindZ);
|
||||
stmt->SetData(6, m_homebindO);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
LOG_DEBUG("entities.player", "Setting player home position - mapid: {}, areaid: {}, X: {}, Y: {}, Z: {}",
|
||||
m_homebindMapId, m_homebindAreaId, m_homebindX, m_homebindY, m_homebindZ);
|
||||
LOG_DEBUG("entities.player", "Setting player home position - mapid: {}, areaid: {}, X: {}, Y: {}, Z: {}, O: {}",
|
||||
m_homebindMapId, m_homebindAreaId, m_homebindX, m_homebindY, m_homebindZ, m_homebindO);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1019,7 +1019,7 @@ void Player::UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool def
|
||||
|
||||
chance = chance < 1.0f ? 1.0f : chance; // minimum chance to increase skill is 1%
|
||||
|
||||
LOG_DEBUG("entities.player", "Player::UpdateCombatSkills(defence:{}, playerLevel:{}, moblevel:{}) -> ({}/{}) chance to increase skill is {}\%", defence, playerLevel, moblevel, currentSkillValue, currentSkillMax, chance);
|
||||
LOG_DEBUG("entities.player", "Player::UpdateCombatSkills(defence:{}, playerLevel:{}, moblevel:{}) -> ({}/{}) chance to increase skill is {}%", defence, playerLevel, moblevel, currentSkillValue, currentSkillMax, chance);
|
||||
|
||||
if (roll_chance_f(chance))
|
||||
{
|
||||
|
||||
@@ -59,25 +59,31 @@ void Unit::UpdateAllResistances()
|
||||
|
||||
void Unit::UpdateDamagePhysical(WeaponAttackType attType)
|
||||
{
|
||||
float minDamage = 0.0f;
|
||||
float maxDamage = 0.0f;
|
||||
float totalMin = 0.f;
|
||||
float totalMax = 0.f;
|
||||
|
||||
CalculateMinMaxDamage(attType, false, true, minDamage, maxDamage);
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
|
||||
{
|
||||
float tmpMin, tmpMax;
|
||||
CalculateMinMaxDamage(attType, false, true, tmpMin, tmpMax, i);
|
||||
totalMin += tmpMin;
|
||||
totalMax += tmpMax;
|
||||
}
|
||||
|
||||
switch (attType)
|
||||
{
|
||||
case BASE_ATTACK:
|
||||
default:
|
||||
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, minDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, totalMin);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, totalMax);
|
||||
break;
|
||||
case OFF_ATTACK:
|
||||
SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, minDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, maxDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, totalMin);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, totalMax);
|
||||
break;
|
||||
case RANGED_ATTACK:
|
||||
SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, minDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, maxDamage);
|
||||
SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, totalMin);
|
||||
SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, totalMax);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -525,8 +531,23 @@ void Player::UpdateShieldBlockValue()
|
||||
SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
|
||||
}
|
||||
|
||||
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
|
||||
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex)
|
||||
{
|
||||
// Only proto damage, not affected by any mods
|
||||
if (damageIndex != 0)
|
||||
{
|
||||
minDamage = 0.0f;
|
||||
maxDamage = 0.0f;
|
||||
|
||||
if (!IsInFeralForm() && CanUseAttackType(attType))
|
||||
{
|
||||
minDamage = GetWeaponDamageRange(attType, MINDAMAGE, damageIndex);
|
||||
maxDamage = GetWeaponDamageRange(attType, MAXDAMAGE, damageIndex);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UnitMods unitMod;
|
||||
|
||||
switch (attType)
|
||||
@@ -1075,8 +1096,16 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
|
||||
void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex /*= 0*/)
|
||||
{
|
||||
// creatures only have one damage
|
||||
if (damageIndex != 0)
|
||||
{
|
||||
minDamage = 0.f;
|
||||
maxDamage = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
UnitMods unitMod;
|
||||
float variance = 1.0f;
|
||||
switch (attType)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,7 @@
|
||||
#include "FollowerRefMgr.h"
|
||||
#include "FollowerReference.h"
|
||||
#include "HostileRefMgr.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "Object.h"
|
||||
#include "Optional.h"
|
||||
@@ -251,7 +252,9 @@ enum UnitModifierType
|
||||
enum WeaponDamageRange
|
||||
{
|
||||
MINDAMAGE,
|
||||
MAXDAMAGE
|
||||
MAXDAMAGE,
|
||||
|
||||
MAX_WEAPON_DAMAGE_RANGE
|
||||
};
|
||||
|
||||
enum UnitMods
|
||||
@@ -762,9 +765,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 +876,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 +1344,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 +1554,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 +1584,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;
|
||||
@@ -2093,10 +2107,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 +2195,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 +2217,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 +2506,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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1702,7 +1702,7 @@ void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recv_data*/)
|
||||
_player->BuildPlayerRepop();
|
||||
_player->ResurrectPlayer(1.0f);
|
||||
_player->SpawnCorpseBones();
|
||||
_player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation());
|
||||
_player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->m_homebindO);
|
||||
}
|
||||
|
||||
void WorldSession::HandleInstanceLockResponse(WorldPacket& recvPacket)
|
||||
|
||||
@@ -92,7 +92,7 @@ void WorldSession::HandleMoveWorldportAck()
|
||||
if (!newMap || newMap->CannotEnter(GetPlayer(), false))
|
||||
{
|
||||
LOG_ERROR("network.opcode", "Map {} could not be created for player {}, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUID().ToString());
|
||||
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
|
||||
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->m_homebindO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ void WorldSession::HandleMoveWorldportAck()
|
||||
GetPlayer()->GetName(), GetPlayer()->GetGUID().ToString(), loc.GetMapId());
|
||||
GetPlayer()->ResetMap();
|
||||
GetPlayer()->SetMap(oldMap);
|
||||
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
|
||||
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->m_homebindO);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -196,7 +196,7 @@ public:
|
||||
// and some dependant problems fixed before it can replace old proc system (for example cooldown handling)
|
||||
// currently proc system functionality is implemented in Unit::ProcDamageAndSpell
|
||||
bool IsProcOnCooldown() const;
|
||||
void AddProcCooldown(uint32 msec);
|
||||
void AddProcCooldown(Milliseconds msec);
|
||||
bool IsUsingCharges() const { return m_isUsingCharges; }
|
||||
void SetUsingCharges(bool val) { m_isUsingCharges = val; }
|
||||
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
|
||||
@@ -1344,7 +1344,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
|
||||
break;
|
||||
case TARGET_DEST_HOME:
|
||||
if (Player* playerCaster = m_caster->ToPlayer())
|
||||
dest = SpellDestination(playerCaster->m_homebindX, playerCaster->m_homebindY, playerCaster->m_homebindZ, playerCaster->GetOrientation(), playerCaster->m_homebindMapId);
|
||||
dest = SpellDestination(playerCaster->m_homebindX, playerCaster->m_homebindY, playerCaster->m_homebindZ, playerCaster->m_homebindO, playerCaster->m_homebindMapId);
|
||||
break;
|
||||
case TARGET_DEST_DB:
|
||||
if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, effIndex))
|
||||
@@ -2428,9 +2428,11 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
|
||||
// Calculate hit result
|
||||
if (m_originalCaster)
|
||||
{
|
||||
targetInfo.missCondition = m_originalCaster->SpellHitResult(target, m_spellInfo, m_canReflect);
|
||||
targetInfo.missCondition = m_originalCaster->SpellHitResult(target, this, m_canReflect);
|
||||
if (m_skipCheck && targetInfo.missCondition != SPELL_MISS_IMMUNE)
|
||||
{
|
||||
targetInfo.missCondition = SPELL_MISS_NONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
targetInfo.missCondition = SPELL_MISS_EVADE; //SPELL_MISS_NONE;
|
||||
@@ -2458,7 +2460,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
|
||||
if (targetInfo.missCondition == SPELL_MISS_REFLECT)
|
||||
{
|
||||
// Calculate reflected spell result on caster
|
||||
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect);
|
||||
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, this, m_canReflect);
|
||||
|
||||
if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell
|
||||
targetInfo.reflectResult = SPELL_MISS_PARRY;
|
||||
@@ -2971,8 +2973,10 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
|
||||
return SPELL_MISS_EVADE;
|
||||
|
||||
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
|
||||
if (m_spellInfo->Speed && ((m_damage > 0 && unit->IsImmunedToDamage(m_spellInfo)) || unit->IsImmunedToSchool(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo)))
|
||||
if (m_spellInfo->Speed && ((m_damage > 0 && unit->IsImmunedToDamage(this)) || unit->IsImmunedToSchool(this) || unit->IsImmunedToSpell(m_spellInfo, this)))
|
||||
{
|
||||
return SPELL_MISS_IMMUNE;
|
||||
}
|
||||
|
||||
// disable effects to which unit is immune
|
||||
SpellMissInfo returnVal = SPELL_MISS_IMMUNE;
|
||||
|
||||
@@ -589,6 +589,8 @@ public:
|
||||
|
||||
[[nodiscard]] TriggerCastFlags GetTriggeredCastFlags() const { return _triggeredCastFlags; }
|
||||
|
||||
[[nodiscard]] SpellSchoolMask GetSpellSchoolMask() const { return m_spellSchoolMask; }
|
||||
|
||||
protected:
|
||||
bool HasGlobalCooldown() const;
|
||||
void TriggerGlobalCooldown();
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -4415,6 +4415,12 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AuraInterruptFlags &= ~AURA_INTERRUPT_FLAG_NOT_ABOVEWATER;
|
||||
});
|
||||
|
||||
// Summon Worm
|
||||
ApplySpellFix({ 518, 25831, 25832 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].MiscValueB = 64;
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -898,11 +898,11 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
|
||||
bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
|
||||
{
|
||||
// proc type doesn't match
|
||||
if (!(eventInfo.GetTypeMask() & procEntry.typeMask))
|
||||
if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags))
|
||||
return false;
|
||||
|
||||
// check XP or honor target requirement
|
||||
if (procEntry.attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)
|
||||
if (procEntry.AttributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)
|
||||
if (Player* actor = eventInfo.GetActor()->ToPlayer())
|
||||
if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
|
||||
return false;
|
||||
@@ -912,37 +912,37 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE
|
||||
return true;
|
||||
|
||||
// check school mask (if set) for other trigger types
|
||||
if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask))
|
||||
if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask))
|
||||
return false;
|
||||
|
||||
// check spell family name/flags (if set) for spells
|
||||
if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION))
|
||||
{
|
||||
if (procEntry.spellFamilyName && (procEntry.spellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName))
|
||||
if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName))
|
||||
return false;
|
||||
|
||||
if (procEntry.spellFamilyMask && !(procEntry.spellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags))
|
||||
if (procEntry.SpellFamilyMask && !(procEntry.SpellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check spell type mask (if set)
|
||||
if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))
|
||||
{
|
||||
if (procEntry.spellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.spellTypeMask))
|
||||
if (procEntry.SpellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.SpellTypeMask))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check spell phase mask
|
||||
if (eventInfo.GetTypeMask() & REQ_SPELL_PHASE_PROC_FLAG_MASK)
|
||||
{
|
||||
if (!(eventInfo.GetSpellPhaseMask() & procEntry.spellPhaseMask))
|
||||
if (!(eventInfo.GetSpellPhaseMask() & procEntry.SpellPhaseMask))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check hit mask (on taken hit or on done hit, but not on spell cast phase)
|
||||
if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)))
|
||||
{
|
||||
uint32 hitMask = procEntry.hitMask;
|
||||
uint32 hitMask = procEntry.HitMask;
|
||||
// get default values if hit mask not set
|
||||
if (!hitMask)
|
||||
{
|
||||
@@ -1833,8 +1833,8 @@ void SpellMgr::LoadSpellProcs()
|
||||
|
||||
mSpellProcMap.clear(); // need for reload case
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
||||
QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc");
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
||||
QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 Spell Proc Conditions And Data. DB table `spell_proc` Is Empty.");
|
||||
@@ -1874,21 +1874,20 @@ void SpellMgr::LoadSpellProcs()
|
||||
|
||||
SpellProcEntry baseProcEntry;
|
||||
|
||||
baseProcEntry.schoolMask = fields[1].Get<int8>();
|
||||
baseProcEntry.spellFamilyName = fields[2].Get<uint16>();
|
||||
baseProcEntry.spellFamilyMask[0] = fields[3].Get<uint32>();
|
||||
baseProcEntry.spellFamilyMask[1] = fields[4].Get<uint32>();
|
||||
baseProcEntry.spellFamilyMask[2] = fields[5].Get<uint32>();
|
||||
baseProcEntry.typeMask = fields[6].Get<uint32>();
|
||||
baseProcEntry.spellTypeMask = fields[7].Get<uint32>();
|
||||
baseProcEntry.spellPhaseMask = fields[8].Get<uint32>();
|
||||
baseProcEntry.hitMask = fields[9].Get<uint32>();
|
||||
baseProcEntry.attributesMask = fields[10].Get<uint32>();
|
||||
baseProcEntry.ratePerMinute = fields[11].Get<float>();
|
||||
baseProcEntry.chance = fields[12].Get<float>();
|
||||
float cooldown = fields[13].Get<float>();
|
||||
baseProcEntry.cooldown = uint32(cooldown);
|
||||
baseProcEntry.charges = fields[14].Get<uint32>();
|
||||
baseProcEntry.SchoolMask = fields[1].Get<int8>();
|
||||
baseProcEntry.SpellFamilyName = fields[2].Get<uint16>();
|
||||
baseProcEntry.SpellFamilyMask[0] = fields[3].Get<uint32>();
|
||||
baseProcEntry.SpellFamilyMask[1] = fields[4].Get<uint32>();
|
||||
baseProcEntry.SpellFamilyMask[2] = fields[5].Get<uint32>();
|
||||
baseProcEntry.ProcFlags = fields[6].Get<uint32>();
|
||||
baseProcEntry.SpellTypeMask = fields[7].Get<uint32>();
|
||||
baseProcEntry.SpellPhaseMask = fields[8].Get<uint32>();
|
||||
baseProcEntry.HitMask = fields[9].Get<uint32>();
|
||||
baseProcEntry.AttributesMask = fields[10].Get<uint32>();
|
||||
baseProcEntry.ProcsPerMinute = fields[11].Get<float>();
|
||||
baseProcEntry.Chance = fields[12].Get<float>();
|
||||
baseProcEntry.Cooldown = Milliseconds(fields[13].Get<uint32>());
|
||||
baseProcEntry.Charges = fields[14].Get<uint32>();
|
||||
|
||||
while (spellInfo)
|
||||
{
|
||||
@@ -1900,56 +1899,51 @@ void SpellMgr::LoadSpellProcs()
|
||||
SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
|
||||
|
||||
// take defaults from dbcs
|
||||
if (!procEntry.typeMask)
|
||||
procEntry.typeMask = spellInfo->ProcFlags;
|
||||
if (!procEntry.charges)
|
||||
procEntry.charges = spellInfo->ProcCharges;
|
||||
if (!procEntry.chance && !procEntry.ratePerMinute)
|
||||
procEntry.chance = float(spellInfo->ProcChance);
|
||||
if (!procEntry.ProcFlags)
|
||||
procEntry.ProcFlags = spellInfo->ProcFlags;
|
||||
if (!procEntry.Charges)
|
||||
procEntry.Charges = spellInfo->ProcCharges;
|
||||
if (!procEntry.Chance && !procEntry.ProcsPerMinute)
|
||||
procEntry.Chance = float(spellInfo->ProcChance);
|
||||
|
||||
// validate data
|
||||
if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `schoolMask` set: {}", spellId, procEntry.schoolMask);
|
||||
if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellFamilyName` set: {}", spellId, procEntry.spellFamilyName);
|
||||
if (procEntry.chance < 0)
|
||||
if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SchoolMask` set: {}", spellId, procEntry.SchoolMask);
|
||||
if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellFamilyName` set: {}", spellId, procEntry.SpellFamilyName);
|
||||
if (procEntry.Chance < 0)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `chance` field", spellId);
|
||||
procEntry.chance = 0;
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `Chance` field", spellId);
|
||||
procEntry.Chance = 0;
|
||||
}
|
||||
if (procEntry.ratePerMinute < 0)
|
||||
if (procEntry.ProcsPerMinute < 0)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `ratePerMinute` field", spellId);
|
||||
procEntry.ratePerMinute = 0;
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `ProcsPerMinute` field", spellId);
|
||||
procEntry.ProcsPerMinute = 0;
|
||||
}
|
||||
if (cooldown < 0)
|
||||
if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellId);
|
||||
if (procEntry.Charges > 99)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `cooldown` field", spellId);
|
||||
procEntry.cooldown = 0;
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has too big value in `Charges` field", spellId);
|
||||
procEntry.Charges = 99;
|
||||
}
|
||||
if (procEntry.chance == 0 && procEntry.ratePerMinute == 0)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellId);
|
||||
if (procEntry.charges > 99)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has too big value in `charges` field", spellId);
|
||||
procEntry.charges = 99;
|
||||
}
|
||||
if (!procEntry.typeMask)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `typeMask` value defined, proc will not be triggered", spellId);
|
||||
if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellTypeMask` set: {}", spellId, procEntry.spellTypeMask);
|
||||
if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellId);
|
||||
if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellId);
|
||||
if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellPhaseMask` set: {}", spellId, procEntry.spellPhaseMask);
|
||||
if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellId);
|
||||
if (procEntry.hitMask & ~PROC_HIT_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `hitMask` set: {}", spellId, procEntry.hitMask);
|
||||
if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellId);
|
||||
if (!procEntry.ProcFlags)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `ProcFlags` value defined, proc will not be triggered", spellId);
|
||||
if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellTypeMask` set: {}", spellId, procEntry.SpellTypeMask);
|
||||
if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellTypeMask` value defined, but it won't be used for defined `ProcFlags` value", spellId);
|
||||
if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `SpellPhaseMask` value defined, but it's required for defined `ProcFlags` value, proc will not be triggered", spellId);
|
||||
if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellPhaseMask` set: {}", spellId, procEntry.SpellPhaseMask);
|
||||
if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellPhaseMask` value defined, but it won't be used for defined `ProcFlags` value", spellId);
|
||||
if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `HitMask` set: {}", spellId, procEntry.HitMask);
|
||||
if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
|
||||
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `HitMask` value defined, but it won't be used for defined `ProcFlags` and `SpellPhaseMask` values", spellId);
|
||||
|
||||
mSpellProcMap[spellInfo->Id] = procEntry;
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ enum ProcFlagsHit
|
||||
PROC_HIT_REFLECT = 0x0000800,
|
||||
PROC_HIT_INTERRUPT = 0x0001000, // (not used atm)
|
||||
PROC_HIT_FULL_BLOCK = 0x0002000,
|
||||
PROC_HIT_MASK_ALL = 0x2FFF,
|
||||
PROC_HIT_MASK_ALL = 0x0002FFF,
|
||||
};
|
||||
|
||||
enum ProcAttributes
|
||||
@@ -288,18 +288,18 @@ typedef std::unordered_map<uint32, SpellProcEventEntry> SpellProcEventMap;
|
||||
|
||||
struct SpellProcEntry
|
||||
{
|
||||
uint32 schoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
|
||||
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName
|
||||
flag96 spellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags
|
||||
uint32 typeMask; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags
|
||||
uint32 spellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType
|
||||
uint32 spellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase
|
||||
uint32 hitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit
|
||||
uint32 attributesMask; // bitmask, see ProcAttributes
|
||||
float ratePerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60
|
||||
float chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set
|
||||
uint32 cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura
|
||||
uint32 charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite
|
||||
uint32 SchoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
|
||||
uint32 SpellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName
|
||||
flag96 SpellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags
|
||||
uint32 ProcFlags; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags
|
||||
uint32 SpellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType
|
||||
uint32 SpellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase
|
||||
uint32 HitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit
|
||||
uint32 AttributesMask; // bitmask, see ProcAttributes
|
||||
float ProcsPerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60
|
||||
float Chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if ProcsPerMinute set
|
||||
Milliseconds Cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura
|
||||
uint32 Charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32, SpellProcEntry> SpellProcMap;
|
||||
|
||||
@@ -1399,7 +1399,7 @@ public:
|
||||
|
||||
if (location->empty() || *location == "inn")
|
||||
{
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ public:
|
||||
else if (targetGuid)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt->SetData(0, uint16(AT_LOGIN_NONE | AT_LOGIN_RESET_PET_TALENTS));
|
||||
stmt->SetData(0, uint16(AT_LOGIN_RESET_TALENTS | AT_LOGIN_RESET_PET_TALENTS));
|
||||
stmt->SetData(1, targetGuid.GetCounter());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ public:
|
||||
if (where.index() == 1) // References target's homebind
|
||||
{
|
||||
if (Player* target = player->GetConnectedPlayer())
|
||||
target->TeleportTo(target->m_homebindMapId, target->m_homebindX, target->m_homebindY, target->m_homebindZ, target->GetOrientation());
|
||||
target->TeleportTo(target->m_homebindMapId, target->m_homebindX, target->m_homebindY, target->m_homebindZ, target->m_homebindO);
|
||||
else
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_HOMEBIND);
|
||||
|
||||
+5
-1
@@ -250,7 +250,11 @@ public:
|
||||
|
||||
if (bossId == DATA_MAJORDOMO_EXECUTUS && state == DONE)
|
||||
{
|
||||
DoRespawnGameObject(_cacheOfTheFirelordGUID, 7 * DAY);
|
||||
if (GameObject* cache = instance->GetGameObject(_cacheOfTheFirelordGUID))
|
||||
{
|
||||
cache->SetRespawnTime(7 * DAY);
|
||||
cache->SetLootRecipient(instance);
|
||||
}
|
||||
}
|
||||
else if (bossId == DATA_GOLEMAGG)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@ EndScriptData */
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "temple_of_ahnqiraj.h"
|
||||
|
||||
@@ -101,6 +102,7 @@ enum Misc
|
||||
{
|
||||
MAX_TENTACLE_GROUPS = 5,
|
||||
NPC_TRIGGER = 15384,
|
||||
NPC_EXIT_TRIGGER = 15800
|
||||
};
|
||||
|
||||
enum Yells
|
||||
@@ -218,6 +220,16 @@ struct boss_eye_of_cthun : public BossAI
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
|
||||
if (Creature* cthun = instance->GetCreature(DATA_CTHUN))
|
||||
{
|
||||
cthun->AI()->JustSummoned(summon);
|
||||
}
|
||||
}
|
||||
|
||||
void ScheduleTasks()
|
||||
{
|
||||
_scheduler.
|
||||
@@ -249,7 +261,7 @@ struct boss_eye_of_cthun : public BossAI
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
|
||||
{
|
||||
if (Creature* tentacle = me->SummonCreature(NPC_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 1000))
|
||||
if (Creature* tentacle = me->SummonCreature(NPC_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
|
||||
{
|
||||
tentacle->AI()->AttackStart(target);
|
||||
}
|
||||
@@ -273,6 +285,9 @@ struct boss_eye_of_cthun : public BossAI
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
me->SetTarget(ObjectGuid::Empty);
|
||||
|
||||
//Freeze animation
|
||||
DoCast(me, SPELL_FREEZE_ANIM, true);
|
||||
|
||||
_scheduler.Schedule(1s, [this](TaskContext /*task*/)
|
||||
{
|
||||
//Select random target for dark beam to start on
|
||||
@@ -283,14 +298,9 @@ struct boss_eye_of_cthun : public BossAI
|
||||
DarkGlareTick = 0;
|
||||
ClockWise = RAND(true, false);
|
||||
|
||||
me->SetTarget(target->GetGUID());
|
||||
|
||||
//Add red coloration to C'thun
|
||||
DoCast(me, SPELL_RED_COLORATION, true);
|
||||
|
||||
//Freeze animation
|
||||
DoCast(me, SPELL_FREEZE_ANIM, true);
|
||||
|
||||
me->StopMoving();
|
||||
me->SetFacingToObject(target);
|
||||
me->SetOrientation(DarkGlareAngle);
|
||||
@@ -301,19 +311,12 @@ struct boss_eye_of_cthun : public BossAI
|
||||
me->SetTarget(ObjectGuid::Empty);
|
||||
me->StopMoving();
|
||||
|
||||
if (ClockWise)
|
||||
{
|
||||
me->SetFacingTo(DarkGlareAngle + DarkGlareTick * float(M_PI) / 35);
|
||||
me->SetOrientation(DarkGlareAngle + DarkGlareTick * float(M_PI) / 35);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
me->SetFacingTo(DarkGlareAngle - DarkGlareTick * float(M_PI) / 35);
|
||||
me->SetOrientation(DarkGlareAngle - DarkGlareTick * float(M_PI) / 35);
|
||||
}
|
||||
float angle = ClockWise ? DarkGlareAngle + DarkGlareTick * float(M_PI) / 35 : DarkGlareAngle - DarkGlareTick * float(M_PI) / 35;
|
||||
me->SetFacingTo(angle);
|
||||
me->SetOrientation(angle);
|
||||
|
||||
DoCastSelf(SPELL_DARK_GLARE);
|
||||
|
||||
++DarkGlareTick;
|
||||
|
||||
if (tasker.GetRepeatCounter() >= 35)
|
||||
@@ -344,7 +347,7 @@ struct boss_eye_of_cthun : public BossAI
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
//Only if it will kill
|
||||
if (damage < me->GetHealth())
|
||||
if (damage < me->GetHealth() || !me->GetHealth())
|
||||
return;
|
||||
|
||||
//Fake death in phase 0 or 1 (green beam or dark glare phase)
|
||||
@@ -366,10 +369,13 @@ struct boss_eye_of_cthun : public BossAI
|
||||
me->RemoveAllAuras();
|
||||
_scheduler.CancelAll();
|
||||
|
||||
if (Creature* cthun = instance->GetCreature(DATA_CTHUN))
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
cthun->AI()->DoAction(ACTION_START_PHASE_TWO);
|
||||
}
|
||||
if (Creature* cthun = instance->GetCreature(DATA_CTHUN))
|
||||
{
|
||||
cthun->AI()->DoAction(ACTION_START_PHASE_TWO);
|
||||
}
|
||||
}, 3s);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -466,7 +472,7 @@ struct boss_cthun : public BossAI
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID))
|
||||
{
|
||||
//Spawn claw tentacle on the random target
|
||||
if (Creature* spawned = me->SummonCreature(NPC_GIANT_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
|
||||
if (Creature* spawned = me->SummonCreature(NPC_GIANT_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
|
||||
{
|
||||
spawned->AI()->AttackStart(target);
|
||||
}
|
||||
@@ -478,7 +484,7 @@ struct boss_cthun : public BossAI
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID))
|
||||
{
|
||||
//Spawn claw tentacle on the random target
|
||||
if (Creature* spawned = me->SummonCreature(NPC_GIANT_EYE_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
|
||||
if (Creature* spawned = me->SummonCreature(NPC_GIANT_EYE_TENTACLE, *target, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
|
||||
{
|
||||
spawned->AI()->AttackStart(target);
|
||||
}
|
||||
@@ -534,6 +540,11 @@ struct boss_cthun : public BossAI
|
||||
{
|
||||
pPortal->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
if (Creature* eye = instance->GetCreature(DATA_EYE_OF_CTHUN))
|
||||
{
|
||||
eye->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override
|
||||
@@ -560,11 +571,11 @@ struct boss_cthun : public BossAI
|
||||
ScheduleTasks();
|
||||
//Remove purple coloration
|
||||
me->RemoveAurasDueToSpell(SPELL_PURPLE_COLORATION);
|
||||
|
||||
DoCastSelf(SPELL_CARAPACE_CTHUN, true);
|
||||
//Spawn flesh tentacle
|
||||
for (uint8 i = 0; i < 2; i++)
|
||||
{
|
||||
me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN);
|
||||
me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -921,6 +932,43 @@ private:
|
||||
ObjectGuid _portalGUID;
|
||||
};
|
||||
|
||||
class spell_cthun_dark_glare : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_cthun_dark_glare);
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
targets.remove_if([caster](WorldObject const* target) { return !caster->HasInLine(target, 5.0f); });
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_cthun_dark_glare::FilterTargets, EFFECT_ALL, TARGET_UNIT_CONE_ENEMY_24);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_cthun_digestive_acid : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_cthun_digestive_acid);
|
||||
|
||||
void OnPeriodic(AuraEffect const* /*aurEff*/)
|
||||
{
|
||||
if (InstanceScript* instance = GetUnitOwner()->GetInstanceScript())
|
||||
{
|
||||
if (Creature* cthun = instance->GetCreature(DATA_CTHUN))
|
||||
{
|
||||
cthun->CastSpell(GetUnitOwner(), SPELL_DIGESTIVE_ACID, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_cthun_digestive_acid::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
|
||||
}
|
||||
};
|
||||
|
||||
// 4033 - At C'thun's stomach
|
||||
class at_cthun_stomach_exit : public AreaTriggerScript
|
||||
{
|
||||
@@ -933,30 +981,37 @@ public:
|
||||
{
|
||||
if (Creature* cthun = instance->GetCreature(DATA_CTHUN))
|
||||
{
|
||||
player->CastSpell(player, SPELL_RUBBLE_ROCKY, true);
|
||||
|
||||
player->m_Events.AddEventAtOffset([player]()
|
||||
if (Creature* trigger = player->FindNearestCreature(NPC_TRIGGER, 15.0f))
|
||||
{
|
||||
if (Creature* trigger = player->FindNearestCreature(NPC_TRIGGER, 15.0f))
|
||||
trigger->CastSpell(player, SPELL_EXIT_STOMACH, true);
|
||||
|
||||
if (Creature* exittrigger = player->FindNearestCreature(NPC_EXIT_TRIGGER, 15.0f))
|
||||
{
|
||||
trigger->CastSpell(player, SPELL_EXIT_STOMACH, true);
|
||||
exittrigger->CastSpell(player, SPELL_RUBBLE_ROCKY, true);
|
||||
}
|
||||
}, 3s);
|
||||
|
||||
player->m_Events.AddEventAtOffset([player]()
|
||||
{
|
||||
player->JumpTo(0.0f, 80.0f, false);
|
||||
}, 5s);
|
||||
}
|
||||
|
||||
player->m_Events.AddEventAtOffset([player, cthun]()
|
||||
{
|
||||
if (cthun)
|
||||
if (Creature* trigger = player->FindNearestCreature(NPC_EXIT_TRIGGER, 10.0f))
|
||||
{
|
||||
player->NearTeleportTo(cthun->GetPositionX(), cthun->GetPositionY(), cthun->GetPositionZ() + 10, float(rand32() % 6));
|
||||
}
|
||||
player->JumpTo(0.0f, 80.0f, false);
|
||||
|
||||
player->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID);
|
||||
}, 6s);
|
||||
player->m_Events.AddEventAtOffset([player, cthun]()
|
||||
{
|
||||
if (cthun)
|
||||
{
|
||||
player->NearTeleportTo(cthun->GetPositionX(), cthun->GetPositionY(), cthun->GetPositionZ() + 10, float(rand32() % 6));
|
||||
}
|
||||
|
||||
player->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID);
|
||||
}, 1s);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->m_Events.KillAllEvents(false);
|
||||
}
|
||||
}, 3s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,7 +1030,10 @@ public:
|
||||
{
|
||||
if (Creature* cthun = instance->GetCreature(DATA_CTHUN))
|
||||
{
|
||||
cthun->CastSpell(player, SPELL_SPIT_OUT, true);
|
||||
if (cthun->IsAlive())
|
||||
{
|
||||
cthun->CastSpell(player, SPELL_SPIT_OUT, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -991,6 +1049,8 @@ void AddSC_boss_cthun()
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_claw_tentacle);
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_giant_claw_tentacle);
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_giant_eye_tentacle);
|
||||
RegisterSpellScript(spell_cthun_dark_glare);
|
||||
RegisterSpellScript(spell_cthun_digestive_acid);
|
||||
new at_cthun_stomach_exit();
|
||||
new at_cthun_center();
|
||||
}
|
||||
|
||||
@@ -49,7 +49,10 @@ enum Events
|
||||
|
||||
struct boss_huhuran : public BossAI
|
||||
{
|
||||
boss_huhuran(Creature* creature) : BossAI(creature, DATA_HUHURAN) { }
|
||||
boss_huhuran(Creature* creature) : BossAI(creature, DATA_HUHURAN)
|
||||
{
|
||||
me->m_CombatDistance = 90.f;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
|
||||
@@ -78,8 +78,15 @@ struct npc_ouro_spawner : public ScriptedAI
|
||||
// Spawn Ouro on LoS check
|
||||
if (!hasSummoned && who->GetTypeId() == TYPEID_PLAYER && me->IsWithinDistInMap(who, 40.0f) && !who->ToPlayer()->IsGameMaster())
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_OURO);
|
||||
hasSummoned = true;
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
{
|
||||
Creature* ouro = instance->GetCreature(DATA_OURO);
|
||||
if (instance->GetBossState(DATA_OURO) != IN_PROGRESS && !ouro)
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_OURO);
|
||||
hasSummoned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
@@ -129,6 +136,9 @@ struct boss_ouro : public BossAI
|
||||
|
||||
void Submerge()
|
||||
{
|
||||
if (_enraged || _submerged)
|
||||
return;
|
||||
|
||||
me->AttackStop();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
|
||||
@@ -206,6 +216,9 @@ struct boss_ouro : public BossAI
|
||||
})
|
||||
.Schedule(3s, GROUP_PHASE_TRANSITION, [this](TaskContext context)
|
||||
{
|
||||
if (_enraged)
|
||||
return;
|
||||
|
||||
if (!IsPlayerWithinMeleeRange() && !_submerged)
|
||||
{
|
||||
if (_submergeMelee < 10)
|
||||
@@ -214,8 +227,7 @@ struct boss_ouro : public BossAI
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_enraged)
|
||||
Submerge();
|
||||
Submerge();
|
||||
_submergeMelee = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
@@ -100,6 +101,7 @@ struct boss_viscidus : public BossAI
|
||||
boss_viscidus(Creature* creature) : BossAI(creature, DATA_VISCIDUS)
|
||||
{
|
||||
me->LowerPlayerDamageReq(me->GetMaxHealth());
|
||||
me->m_CombatDistance = 60.f;
|
||||
}
|
||||
|
||||
bool CheckInRoom() override
|
||||
@@ -131,13 +133,25 @@ struct boss_viscidus : public BossAI
|
||||
me->RemoveAurasDueToSpell(SPELL_INVIS_SELF);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType effType, SpellSchoolMask) override
|
||||
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType effType, SpellSchoolMask spellSchoolMask) override
|
||||
{
|
||||
if (me->HealthBelowPct(5))
|
||||
damage = 0;
|
||||
|
||||
if (!attacker || _phase != PHASE_MELEE)
|
||||
if (!attacker)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_phase != PHASE_MELEE)
|
||||
{
|
||||
if (_phase == PHASE_FROST && effType == DIRECT_DAMAGE && (spellSchoolMask & SPELL_SCHOOL_MASK_FROST) != 0)
|
||||
{
|
||||
++_hitcounter;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (effType == DIRECT_DAMAGE)
|
||||
++_hitcounter;
|
||||
@@ -183,14 +197,23 @@ struct boss_viscidus : public BossAI
|
||||
Talk(EMOTE_CRACK);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
||||
void SpellHit(Unit* caster, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spell->Id == SPELL_REJOIN_VISCIDUS)
|
||||
if (spellInfo->Id == SPELL_REJOIN_VISCIDUS)
|
||||
{
|
||||
me->RemoveAuraFromStack(SPELL_VISCIDUS_SHRINKS);
|
||||
}
|
||||
|
||||
if ((spell->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST)
|
||||
SpellSchoolMask spellSchoolMask = spellInfo->GetSchoolMask();
|
||||
if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && spellInfo->EquippedItemSubClassMask & (1 << ITEM_SUBCLASS_WEAPON_WAND))
|
||||
{
|
||||
if (Item* pItem = caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK))
|
||||
{
|
||||
spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->Damage[0].DamageType);
|
||||
}
|
||||
}
|
||||
|
||||
if ((spellSchoolMask & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST)
|
||||
{
|
||||
++_hitcounter;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ ObjectData const creatureData[] =
|
||||
{ NPC_SARTURA, DATA_SARTURA },
|
||||
{ NPC_CTHUN, DATA_CTHUN },
|
||||
{ NPC_EYE_OF_CTHUN, DATA_EYE_OF_CTHUN },
|
||||
{ NPC_OURO, DATA_OURO },
|
||||
{ NPC_OURO_SPAWNER, DATA_OURO_SPAWNER },
|
||||
{ NPC_MASTERS_EYE, DATA_MASTERS_EYE },
|
||||
{ NPC_VEKLOR, DATA_VEKLOR },
|
||||
|
||||
@@ -179,7 +179,7 @@ public:
|
||||
void AddSentinelsNear(Unit* /*nears*/)
|
||||
{
|
||||
std::list<Creature*> assistList;
|
||||
me->GetCreatureListWithEntryInGrid(assistList, 15264, 70.0f);
|
||||
me->GetCreatureListWithEntryInGrid(assistList, 15264, 100.0f);
|
||||
|
||||
if (assistList.empty())
|
||||
return;
|
||||
|
||||
@@ -273,7 +273,7 @@ struct npc_obsidian_eradicator : public ScriptedAI
|
||||
|
||||
if (me->GetPowerPct(POWER_MANA) >= 100.f)
|
||||
{
|
||||
DoCastAOE(SPELL_SHOCK_BLAST, true);
|
||||
DoCastAOE(SPELL_SHOCK_BLAST);
|
||||
}
|
||||
|
||||
context.Repeat(3500ms);
|
||||
@@ -406,7 +406,7 @@ struct npc_obsidian_nullifier : public ScriptedAI
|
||||
|
||||
if (me->GetPowerPct(POWER_MANA) >= 100.f)
|
||||
{
|
||||
DoCastAOE(SPELL_NULLIFY, true);
|
||||
DoCastAOE(SPELL_NULLIFY);
|
||||
}
|
||||
|
||||
context.Repeat(6s);
|
||||
@@ -445,6 +445,19 @@ struct npc_ahnqiraji_critter : public ScriptedAI
|
||||
me->RestoreFaction();
|
||||
|
||||
_scheduler.CancelAll();
|
||||
|
||||
// Don't attack nearby players randomly if they are the Twin's pet bugs.
|
||||
if (CreatureData const* crData = me->GetCreatureData())
|
||||
{
|
||||
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(crData->id1, me->GetSpawnId());
|
||||
ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid);
|
||||
|
||||
if (targetGuid.GetEntry() == NPC_VEKLOR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_scheduler.Schedule(100ms, [this](TaskContext context)
|
||||
{
|
||||
if (Player* player = me->SelectNearestPlayer(10.f))
|
||||
|
||||
@@ -750,8 +750,8 @@ public:
|
||||
InstanceScript* instance = creature->GetInstanceScript();
|
||||
if (instance && instance->GetBossState(DATA_DEATHBRINGER_SAURFANG) != DONE && instance->GetBossState(DATA_DEATHBRINGER_SAURFANG) != IN_PROGRESS)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "We are ready to go, High Overlord. The Lich King must fall!", 631, -ACTION_START_EVENT);
|
||||
SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
|
||||
AddGossipItemFor(player, 10953, 0, GOSSIP_SENDER_INFO, -ACTION_START_EVENT);
|
||||
SendGossipMenuFor(player, player->GetGossipTextId(10953, creature), creature->GetGUID());
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -964,8 +964,8 @@ public:
|
||||
InstanceScript* instance = creature->GetInstanceScript();
|
||||
if (instance && instance->GetBossState(DATA_DEATHBRINGER_SAURFANG) != DONE && instance->GetBossState(DATA_DEATHBRINGER_SAURFANG) != IN_PROGRESS)
|
||||
{
|
||||
AddGossipItemFor(player, 0, "Let it begin...", 631, -ACTION_START_EVENT + 1);
|
||||
SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
|
||||
AddGossipItemFor(player, 10933, 0, GOSSIP_SENDER_INFO, -ACTION_START_EVENT + 1);
|
||||
SendGossipMenuFor(player, player->GetGossipTextId(10933, creature), creature->GetGUID());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -119,7 +119,7 @@ public:
|
||||
if (!PlayerList.IsEmpty())
|
||||
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
|
||||
if (Player* player = i->GetSource())
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,10 +648,13 @@ class spell_dk_dancing_rune_weapon : public AuraScript
|
||||
{
|
||||
target = player->GetMeleeHitRedirectTarget(target);
|
||||
CalcDamageInfo damageInfo;
|
||||
player->CalculateMeleeDamage(target, 0, &damageInfo, eventInfo.GetDamageInfo()->GetAttackType());
|
||||
Unit::DealDamageMods(target, damageInfo.damage, &damageInfo.absorb);
|
||||
player->CalculateMeleeDamage(target, &damageInfo, eventInfo.GetDamageInfo()->GetAttackType());
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
|
||||
{
|
||||
Unit::DealDamageMods(target, damageInfo.damages[i].damage, &damageInfo.damages[i].absorb);
|
||||
damageInfo.damages[i].damage /= 2.0f;
|
||||
}
|
||||
damageInfo.attacker = dancingRuneWeapon;
|
||||
damageInfo.damage /= 2.0f;
|
||||
dancingRuneWeapon->SendAttackStateUpdate(&damageInfo);
|
||||
dancingRuneWeapon->DealMeleeDamage(&damageInfo, true);
|
||||
}
|
||||
|
||||
@@ -567,8 +567,14 @@ class spell_warr_rend : public AuraScript
|
||||
// $0.2 * (($MWB + $mwb) / 2 + $AP / 14 * $MWS) bonus per tick
|
||||
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
|
||||
int32 mws = caster->GetAttackTime(BASE_ATTACK);
|
||||
float mwbMin = caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
|
||||
float mwbMax = caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
|
||||
float mwbMin = 0.f;
|
||||
float mwbMax = 0.f;
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
|
||||
{
|
||||
mwbMin += caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE, i);
|
||||
mwbMax += caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE, i);
|
||||
}
|
||||
|
||||
float mwb = ((mwbMin + mwbMax) / 2 + ap * mws / 14000) * 0.2f;
|
||||
amount += int32(caster->ApplyEffectModifiers(GetSpellInfo(), aurEff->GetEffIndex(), mwb));
|
||||
|
||||
|
||||
@@ -2542,6 +2542,64 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum ArcaniteDragonling
|
||||
{
|
||||
SPELL_FLAME_BUFFET = 9658,
|
||||
SPELL_FLAME_BREATH = 8873,
|
||||
|
||||
EVENT_FLAME_BUFFET = 1,
|
||||
EVENT_FLAME_BREATH = 2
|
||||
};
|
||||
|
||||
struct npc_arcanite_dragonling : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
npc_arcanite_dragonling(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
creature->SetCanModifyStats(true);
|
||||
creature->SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetPvP(true);
|
||||
events.Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_FLAME_BUFFET, 4s);
|
||||
events.ScheduleEvent(EVENT_FLAME_BREATH, 12s);
|
||||
}
|
||||
|
||||
void IsSummonedBy(Unit* summoner) override
|
||||
{
|
||||
me->GetMotionMaster()->MoveFollow(summoner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_FLAME_BUFFET:
|
||||
DoCastVictim(SPELL_FLAME_BUFFET);
|
||||
events.Repeat(12s);
|
||||
break;
|
||||
case EVENT_FLAME_BREATH:
|
||||
DoCastVictim(SPELL_FLAME_BREATH);
|
||||
events.Repeat(24s);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_npcs_special()
|
||||
{
|
||||
// Ours
|
||||
@@ -2568,4 +2626,5 @@ void AddSC_npcs_special()
|
||||
new npc_firework();
|
||||
new npc_spring_rabbit();
|
||||
new npc_stable_master();
|
||||
RegisterCreatureAI(npc_arcanite_dragonling);
|
||||
}
|
||||
|
||||
@@ -53,11 +53,10 @@ void RealmList::Close()
|
||||
void RealmList::LoadBuildInfo()
|
||||
{
|
||||
// 0 1 2 3 4 5 6
|
||||
if (QueryResult result = LoginDatabase.Query("SELECT majorVersion, minorVersion, bugfixVersion, hotfixVersion, build, winChecksumSeed, macChecksumSeed FROM build_info ORDER BY build ASC"))
|
||||
if (auto result = LoginDatabase.Query("SELECT majorVersion, minorVersion, bugfixVersion, hotfixVersion, build, winChecksumSeed, macChecksumSeed FROM build_info ORDER BY build ASC"))
|
||||
{
|
||||
do
|
||||
for (auto const& fields : *result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
RealmBuildInfo& build = _builds.emplace_back();
|
||||
build.MajorVersion = fields[0].Get<uint32>();
|
||||
build.MinorVersion = fields[1].Get<uint32>();
|
||||
@@ -87,7 +86,7 @@ void RealmList::LoadBuildInfo()
|
||||
{
|
||||
HexStrToByteArray(macHash, build.MacHash);
|
||||
}
|
||||
} while (result->NextRow());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,11 +148,10 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
|
||||
// Circle through results and add them to the realm map
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
for (auto const& fields : *result)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 realmId = fields[0].Get<uint32>();
|
||||
std::string name = fields[1].Get<std::string>();
|
||||
std::string externalAddressString = fields[2].Get<std::string>();
|
||||
@@ -221,7 +219,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
|
||||
LOG_ERROR("server.authserver", "Realmlist::UpdateRealms has thrown an exception: {}", ex.what());
|
||||
ABORT();
|
||||
}
|
||||
} while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto itr = existingRealms.begin(); itr != existingRealms.end(); ++itr)
|
||||
|
||||
Reference in New Issue
Block a user