Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-10-15 09:59:28 -06:00
committed by GitHub
81 changed files with 4647 additions and 483 deletions
@@ -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
+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; }
+60 -48
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)
@@ -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);
+4 -1
View File
@@ -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))
{
+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);
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
+38 -22
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
@@ -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);
+1 -1
View File
@@ -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)
+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 -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);
}
}
}
+7 -7
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())
+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);
+8 -4
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;
+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();
+21 -7
View File
@@ -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];
+61 -67
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)
{
@@ -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
@@ -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;
}
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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);
@@ -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);
}
}
}
+6 -3
View File
@@ -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);
}
+8 -2
View File
@@ -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));
+59
View File
@@ -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);
}
+5 -7
View File
@@ -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)