Merge branch 'master' into Playerbot
This commit is contained in:
@@ -52,7 +52,7 @@ void UnitAI::DoMeleeAttackIfReady()
|
||||
if (me->isAttackReady())
|
||||
{
|
||||
// xinef: prevent base and off attack in same time, delay attack at 0.2 sec
|
||||
if (me->haveOffhandWeapon())
|
||||
if (me->HasOffhandWeaponForAttack())
|
||||
if (me->getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
|
||||
me->setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
|
||||
|
||||
@@ -60,7 +60,7 @@ void UnitAI::DoMeleeAttackIfReady()
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
|
||||
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
|
||||
if (me->HasOffhandWeaponForAttack() && me->isAttackReady(OFF_ATTACK))
|
||||
{
|
||||
// xinef: delay main hand attack if both will hit at the same time (players code)
|
||||
if (me->getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY)
|
||||
|
||||
@@ -522,17 +522,33 @@ void ScriptedAI::SetEquipmentSlots(bool loadDefault, int32 mainHand /*= EQUIP_NO
|
||||
if (loadDefault)
|
||||
{
|
||||
me->LoadEquipment(me->GetOriginalEquipmentId(), true);
|
||||
if (me->HasWeapon(OFF_ATTACK))
|
||||
me->SetCanDualWield(true);
|
||||
else
|
||||
me->SetCanDualWield(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mainHand >= 0)
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(mainHand));
|
||||
{
|
||||
me->SetVirtualItem(0, uint32(mainHand));
|
||||
me->UpdateDamagePhysical(BASE_ATTACK);
|
||||
}
|
||||
|
||||
if (offHand >= 0)
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(offHand));
|
||||
{
|
||||
me->SetVirtualItem(1, uint32(offHand));
|
||||
if (offHand >= 1)
|
||||
me->SetCanDualWield(true);
|
||||
else
|
||||
me->SetCanDualWield(false);
|
||||
}
|
||||
|
||||
if (ranged >= 0)
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, uint32(ranged));
|
||||
{
|
||||
me->SetVirtualItem(2, uint32(ranged));
|
||||
me->UpdateDamagePhysical(RANGED_ATTACK);
|
||||
}
|
||||
}
|
||||
|
||||
enum eNPCs
|
||||
|
||||
@@ -146,6 +146,7 @@ Battleground::Battleground()
|
||||
m_LastResurrectTime = 0;
|
||||
m_ArenaType = 0;
|
||||
m_IsArena = false;
|
||||
m_IsTemplate = true;
|
||||
m_WinnerId = PVP_TEAM_NEUTRAL;
|
||||
m_StartTime = 0;
|
||||
m_ResetStatTimer = 0;
|
||||
@@ -1006,6 +1007,10 @@ void Battleground::RemovePlayerAtLeave(Player* player)
|
||||
// BG subclass specific code
|
||||
RemovePlayer(player);
|
||||
|
||||
// should remove spirit of redemption
|
||||
if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
|
||||
player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
|
||||
|
||||
// if the player was a match participant
|
||||
if (participant)
|
||||
{
|
||||
@@ -1049,9 +1054,6 @@ void Battleground::RemovePlayerAtLeave(Player* player)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove shapeshift auras
|
||||
player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
|
||||
|
||||
player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE, PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL);
|
||||
|
||||
// Xinef: remove all criterias on bg leave
|
||||
@@ -1821,6 +1823,7 @@ GraveyardStruct const* Battleground::GetClosestGraveyard(Player* player)
|
||||
|
||||
void Battleground::SetBracket(PvPDifficultyEntry const* bracketEntry)
|
||||
{
|
||||
m_IsTemplate = false;
|
||||
m_BracketId = bracketEntry->GetBracketId();
|
||||
SetLevelRange(bracketEntry->minLevel, bracketEntry->maxLevel);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "DBCEnums.h"
|
||||
#include "GameObject.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "World.h"
|
||||
|
||||
class Creature;
|
||||
class GameObject;
|
||||
@@ -47,11 +48,15 @@ struct GraveyardStruct;
|
||||
|
||||
enum BattlegroundDesertionType : uint8
|
||||
{
|
||||
BG_DESERTION_TYPE_LEAVE_BG = 0, // player leaves the BG
|
||||
BG_DESERTION_TYPE_OFFLINE = 1, // player is kicked from BG because offline
|
||||
BG_DESERTION_TYPE_LEAVE_QUEUE = 2, // player is invited to join and refuses to do it
|
||||
BG_DESERTION_TYPE_NO_ENTER_BUTTON = 3, // player is invited to join and do nothing (time expires)
|
||||
BG_DESERTION_TYPE_INVITE_LOGOUT = 4, // player is invited to join and logs out
|
||||
BG_DESERTION_TYPE_LEAVE_BG = 0, // player leaves the BG
|
||||
BG_DESERTION_TYPE_OFFLINE = 1, // player is kicked from BG because offline
|
||||
BG_DESERTION_TYPE_LEAVE_QUEUE = 2, // player is invited to join and refuses to do it
|
||||
BG_DESERTION_TYPE_NO_ENTER_BUTTON = 3, // player is invited to join and do nothing (time expires)
|
||||
BG_DESERTION_TYPE_INVITE_LOGOUT = 4, // player is invited to join and logs out
|
||||
ARENA_DESERTION_TYPE_LEAVE_BG = 5, // player leaves the Arena
|
||||
ARENA_DESERTION_TYPE_LEAVE_QUEUE = 6, // player is invited to join arena and refuses to do it
|
||||
ARENA_DESERTION_TYPE_NO_ENTER_BUTTON = 7, // player is invited to join arena and do nothing (time expires)
|
||||
ARENA_DESERTION_TYPE_INVITE_LOGOUT = 8, // player is invited to join arena and logs out
|
||||
};
|
||||
|
||||
enum BattlegroundMaps
|
||||
@@ -334,8 +339,20 @@ public:
|
||||
[[nodiscard]] uint32 GetMinLevel() const { return m_LevelMin; }
|
||||
[[nodiscard]] uint32 GetMaxLevel() const { return m_LevelMax; }
|
||||
|
||||
[[nodiscard]] bool isTemplate() const { return m_IsTemplate; }
|
||||
[[nodiscard]] bool isMaxLevel() const
|
||||
{
|
||||
// NOTE: this only works when the BG is not a template but the real BG
|
||||
auto maxPlayerLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
||||
return GetMinLevel() <= maxPlayerLevel && maxPlayerLevel <= GetMaxLevel();
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32 GetMaxPlayersPerTeam() const { return m_MaxPlayersPerTeam; }
|
||||
[[nodiscard]] uint32 GetMinPlayersPerTeam() const { return m_MinPlayersPerTeam; }
|
||||
[[nodiscard]] uint32 GetMinPlayersPerTeam() const
|
||||
{
|
||||
auto lowLevelsOverride = sWorld->getIntConfig(CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS);
|
||||
return (lowLevelsOverride && !isTemplate() && !isMaxLevel() && !isArena()) ? lowLevelsOverride : m_MinPlayersPerTeam;
|
||||
}
|
||||
|
||||
[[nodiscard]] int32 GetStartDelayTime() const { return m_StartDelayTime; }
|
||||
[[nodiscard]] uint8 GetArenaType() const { return m_ArenaType; }
|
||||
@@ -655,6 +672,7 @@ private:
|
||||
bool _InBGFreeSlotQueue{ false }; // used to make sure that BG is only once inserted into the BattlegroundMgr.BGFreeSlotQueue[bgTypeId] deque
|
||||
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
|
||||
bool m_IsArena;
|
||||
bool m_IsTemplate;
|
||||
PvPTeamId m_WinnerId;
|
||||
int32 m_StartDelayTime;
|
||||
bool m_IsRated; // is this battle rated?
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include <unordered_map>
|
||||
|
||||
#include "BattlegroundUtils.h"
|
||||
|
||||
/*********************************************************/
|
||||
/*** BATTLEGROUND QUEUE SYSTEM ***/
|
||||
/*********************************************************/
|
||||
@@ -760,7 +762,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundTypeId
|
||||
}
|
||||
|
||||
// get min and max players per team
|
||||
uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
|
||||
uint32 MinPlayersPerTeam = GetMinPlayersPerTeam(bg_template, bracketEntry);
|
||||
uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
|
||||
|
||||
if (bg_template->isArena())
|
||||
@@ -996,7 +998,7 @@ void BattlegroundQueue::BattlegroundQueueAnnouncerUpdate(uint32 diff, Battlegrou
|
||||
_queueAnnouncementTimer[bracket_id] = -1;
|
||||
|
||||
auto bgName = bg_template->GetName();
|
||||
uint32 MaxPlayers = bg_template->GetMinPlayersPerTeam() * 2;
|
||||
uint32 MaxPlayers = GetMinPlayersPerTeam(bg_template, bracketEntry) * 2;
|
||||
uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32) 80);
|
||||
uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32) 80);
|
||||
|
||||
@@ -1047,7 +1049,7 @@ void BattlegroundQueue::SendMessageBGQueue(Player* leader, Battleground* bg, PvP
|
||||
|
||||
BattlegroundBracketId bracketId = bracketEntry->GetBracketId();
|
||||
auto bgName = bg->GetName();
|
||||
uint32 MinPlayers = bg->GetMinPlayersPerTeam();
|
||||
uint32 MinPlayers = GetMinPlayersPerTeam(bg, bracketEntry);
|
||||
uint32 MaxPlayers = MinPlayers * 2;
|
||||
uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32)80);
|
||||
uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32)80);
|
||||
@@ -1357,6 +1359,9 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
sScriptMgr->OnBattlegroundDesertion(player, BG_DESERTION_TYPE_NO_ENTER_BUTTON);
|
||||
}
|
||||
|
||||
if (bg && bg->isArena() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
|
||||
sScriptMgr->OnBattlegroundDesertion(player, ARENA_DESERTION_TYPE_NO_ENTER_BUTTON);
|
||||
|
||||
LOG_DEBUG("bg.battleground", "Battleground: removing player {} from bg queue for instance {} because of not pressing enter battle in time.", player->GetGUID().ToString(), m_BgInstanceGUID);
|
||||
|
||||
player->RemoveBattlegroundQueueId(m_BgQueueTypeId);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "BattlegroundUtils.h"
|
||||
#include "World.h"
|
||||
|
||||
uint32 GetMinPlayersPerTeam(Battleground* bg, PvPDifficultyEntry const* bracketEntry)
|
||||
{
|
||||
// The problem addressed here is that methods such as bg->GetMinLevel() and bg->GetMaxLevel() have a different meaning
|
||||
// according to whether the BG is a template (then it's the value from the `battleground_template` table)
|
||||
// or if it's the real BG (then it's the specific bracket minimum level, e.g. "60" for "60-69").
|
||||
|
||||
if (!bg->isTemplate() || bg->isArena())
|
||||
{
|
||||
return bg->GetMinPlayersPerTeam();
|
||||
}
|
||||
|
||||
auto maxPlayerLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
||||
auto isMaxLevel = bracketEntry->minLevel <= maxPlayerLevel && maxPlayerLevel <= bracketEntry->maxLevel;
|
||||
auto lowLevelsOverride = sWorld->getIntConfig(CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS);
|
||||
|
||||
return (lowLevelsOverride && !isMaxLevel) ? lowLevelsOverride : bg->GetMinPlayersPerTeam();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef BATTLEGROUNDUTILS_H
|
||||
#define BATTLEGROUNDUTILS_H
|
||||
|
||||
#include "Battleground.h"
|
||||
|
||||
uint32 GetMinPlayersPerTeam(Battleground* bg, PvPDifficultyEntry const* bracketEntry);
|
||||
|
||||
#endif // BATTLEGROUNDUTILS_H
|
||||
@@ -524,6 +524,8 @@ bool Creature::InitEntry(uint32 Entry, const CreatureData* data)
|
||||
|
||||
SetFloatValue(UNIT_FIELD_HOVERHEIGHT, cinfo->HoverHeight);
|
||||
|
||||
SetCanDualWield(cinfo->flags_extra & CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK);
|
||||
|
||||
// checked at loading
|
||||
m_defaultMovementType = MovementGeneratorType(cinfo->MovementType);
|
||||
if (!m_wanderDistance && m_defaultMovementType == RANDOM_MOTION_TYPE)
|
||||
@@ -568,6 +570,8 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
|
||||
|
||||
ReplaceAllDynamicFlags(dynamicflags);
|
||||
|
||||
SetCanDualWield(cInfo->flags_extra & CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK);
|
||||
|
||||
SetAttackTime(BASE_ATTACK, cInfo->BaseAttackTime);
|
||||
SetAttackTime(OFF_ATTACK, cInfo->BaseAttackTime);
|
||||
SetAttackTime(RANGED_ATTACK, cInfo->RangeAttackTime);
|
||||
@@ -3173,6 +3177,14 @@ bool Creature::IsImmuneToKnockback() const
|
||||
return cinfo && (cinfo->flags_extra & CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK);
|
||||
}
|
||||
|
||||
bool Creature::HasWeapon(WeaponAttackType type) const
|
||||
{
|
||||
const uint8 slot = uint8(type);
|
||||
ItemEntry const* item = sItemStore.LookupEntry(GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + slot));
|
||||
|
||||
return ((item && item->ClassID == ITEM_CLASS_WEAPON) || (type == OFF_ATTACK && CanDualWield()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the creature's walk mode by removing: MOVEMENTFLAG_WALKING. Infom also the client
|
||||
*/
|
||||
|
||||
@@ -190,6 +190,8 @@ public:
|
||||
void UpdateAttackPowerAndDamage(bool ranged = false) override;
|
||||
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
|
||||
|
||||
bool HasWeapon(WeaponAttackType type) const override;
|
||||
bool HasWeaponForAttack(WeaponAttackType type) const override { return (Unit::HasWeaponForAttack(type) && HasWeapon(type)); }
|
||||
void SetCanDualWield(bool value) override;
|
||||
[[nodiscard]] int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
|
||||
uint8 GetCurrentEquipmentId() { return m_equipmentId; }
|
||||
|
||||
@@ -54,7 +54,7 @@ enum CreatureFlagsExtra : uint32
|
||||
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and 'attack me' effects
|
||||
CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE = 0x00000200, // creature won't update movement flags
|
||||
CREATURE_FLAG_EXTRA_GHOST_VISIBILITY = 0x00000400, // creature will only be visible to dead players
|
||||
CREATURE_FLAG_EXTRA_UNUSED_12 = 0x00000800, /// @todo: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)
|
||||
CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK = 0x00000800, // creature will use offhand attacks
|
||||
CREATURE_FLAG_EXTRA_NO_SELL_VENDOR = 0x00001000, // players can't sell items to this vendor
|
||||
CREATURE_FLAG_EXTRA_IGNORE_COMBAT = 0x00002000,
|
||||
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
|
||||
@@ -77,9 +77,7 @@ enum CreatureFlagsExtra : uint32
|
||||
CREATURE_FLAG_EXTRA_HARD_RESET = 0x80000000,
|
||||
|
||||
// Masks
|
||||
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12), // SKIP
|
||||
|
||||
CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) // SKIP
|
||||
CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~CREATURE_FLAG_EXTRA_DUNGEON_BOSS) // SKIP
|
||||
};
|
||||
|
||||
enum class CreatureGroundMovementType : uint8
|
||||
|
||||
@@ -42,7 +42,7 @@ AC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr
|
||||
case CREATURE_FLAG_EXTRA_NO_TAUNT: return { "CREATURE_FLAG_EXTRA_NO_TAUNT", "CREATURE_FLAG_EXTRA_NO_TAUNT", "creature is immune to taunt auras and 'attack me' effects" };
|
||||
case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return { "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "creature won't update movement flags" };
|
||||
case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return { "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "creature will only be visible to dead players" };
|
||||
case CREATURE_FLAG_EXTRA_UNUSED_12: return { "CREATURE_FLAG_EXTRA_UNUSED_12", "CREATURE_FLAG_EXTRA_UNUSED_12", "/ @todo: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)" };
|
||||
case CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK: return { "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "/ @todo: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)" };
|
||||
case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return { "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "players can't sell items to this vendor" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return { "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "" };
|
||||
case CREATURE_FLAG_EXTRA_WORLDEVENT: return { "CREATURE_FLAG_EXTRA_WORLDEVENT", "CREATURE_FLAG_EXTRA_WORLDEVENT", "custom flag for world event creatures (left room for merging)" };
|
||||
@@ -86,7 +86,7 @@ AC_API_EXPORT CreatureFlagsExtra EnumUtils<CreatureFlagsExtra>::FromIndex(std::s
|
||||
case 8: return CREATURE_FLAG_EXTRA_NO_TAUNT;
|
||||
case 9: return CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE;
|
||||
case 10: return CREATURE_FLAG_EXTRA_GHOST_VISIBILITY;
|
||||
case 11: return CREATURE_FLAG_EXTRA_UNUSED_12;
|
||||
case 11: return CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK;
|
||||
case 12: return CREATURE_FLAG_EXTRA_NO_SELL_VENDOR;
|
||||
case 13: return CREATURE_FLAG_EXTRA_IGNORE_COMBAT;
|
||||
case 14: return CREATURE_FLAG_EXTRA_WORLDEVENT;
|
||||
@@ -127,7 +127,7 @@ AC_API_EXPORT std::size_t EnumUtils<CreatureFlagsExtra>::ToIndex(CreatureFlagsEx
|
||||
case CREATURE_FLAG_EXTRA_NO_TAUNT: return 8;
|
||||
case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return 9;
|
||||
case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return 10;
|
||||
case CREATURE_FLAG_EXTRA_UNUSED_12: return 11;
|
||||
case CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK: return 11;
|
||||
case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return 12;
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return 13;
|
||||
case CREATURE_FLAG_EXTRA_WORLDEVENT: return 14;
|
||||
|
||||
@@ -2725,17 +2725,17 @@ bool WorldObject::GetClosePoint(float& x, float& y, float& z, float size, float
|
||||
return true;
|
||||
}
|
||||
|
||||
Position WorldObject::GetNearPosition(float dist, float angle)
|
||||
Position WorldObject::GetNearPosition(float dist, float angle, bool disableWarning)
|
||||
{
|
||||
Position pos = GetPosition();
|
||||
MovePosition(pos, dist, angle);
|
||||
MovePosition(pos, dist, angle, disableWarning);
|
||||
return pos;
|
||||
}
|
||||
|
||||
Position WorldObject::GetRandomNearPosition(float radius)
|
||||
Position WorldObject::GetRandomNearPosition(float radius, bool disableWarning)
|
||||
{
|
||||
Position pos = GetPosition();
|
||||
MovePosition(pos, radius * (float) rand_norm(), (float) rand_norm() * static_cast<float>(2 * M_PI));
|
||||
MovePosition(pos, radius * (float) rand_norm(), (float) rand_norm() * static_cast<float>(2 * M_PI), disableWarning);
|
||||
return pos;
|
||||
}
|
||||
|
||||
@@ -2773,7 +2773,7 @@ void WorldObject::GetChargeContactPoint(WorldObject const* obj, float& x, float&
|
||||
return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE * GetObjectScale();
|
||||
}
|
||||
|
||||
void WorldObject::MovePosition(Position& pos, float dist, float angle)
|
||||
void WorldObject::MovePosition(Position& pos, float dist, float angle, bool disableWarning)
|
||||
{
|
||||
angle += GetOrientation();
|
||||
float destx, desty, destz, ground, floor;
|
||||
@@ -2783,7 +2783,9 @@ void WorldObject::MovePosition(Position& pos, float dist, float angle)
|
||||
// Prevent invalid coordinates here, position is unchanged
|
||||
if (!Acore::IsValidMapCoord(destx, desty))
|
||||
{
|
||||
LOG_FATAL("entities.object", "WorldObject::MovePosition invalid coordinates X: {} and Y: {} were passed!", destx, desty);
|
||||
if (!disableWarning)
|
||||
LOG_FATAL("entities.object", "WorldObject::MovePosition invalid coordinates X: {} and Y: {} were passed!", destx, desty);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -420,13 +420,13 @@ public:
|
||||
void GetNearPoint(WorldObject const* searcher, float& x, float& y, float& z, float searcher_size, float distance2d, float absAngle, float controlZ = 0, Position const* startPos = nullptr) const;
|
||||
void GetVoidClosePoint(float& x, float& y, float& z, float size, float distance2d = 0, float relAngle = 0, float controlZ = 0) const;
|
||||
bool GetClosePoint(float& x, float& y, float& z, float size, float distance2d = 0, float angle = 0, WorldObject const* forWho = nullptr, bool force = false) const;
|
||||
void MovePosition(Position& pos, float dist, float angle);
|
||||
Position GetNearPosition(float dist, float angle);
|
||||
void MovePosition(Position& pos, float dist, float angle, bool disableWarning = false);
|
||||
Position GetNearPosition(float dist, float angle, bool disableWarning = false);
|
||||
void MovePositionToFirstCollision(Position& pos, float dist, float angle);
|
||||
Position GetFirstCollisionPosition(float startX, float startY, float startZ, float destX, float destY);
|
||||
Position GetFirstCollisionPosition(float destX, float destY, float destZ);
|
||||
Position GetFirstCollisionPosition(float dist, float angle);
|
||||
Position GetRandomNearPosition(float radius);
|
||||
Position GetRandomNearPosition(float radius, bool disableWarning = false);
|
||||
|
||||
void GetContactPoint(WorldObject const* obj, float& x, float& y, float& z, float distance2d = CONTACT_DISTANCE) const;
|
||||
void GetChargeContactPoint(WorldObject const* obj, float& x, float& y, float& z, float distance2d = CONTACT_DISTANCE) const;
|
||||
|
||||
@@ -11347,6 +11347,9 @@ void Player::LeaveBattleground(Battleground* bg)
|
||||
sScriptMgr->OnBattlegroundDesertion(this, BG_DESERTION_TYPE_LEAVE_BG);
|
||||
}
|
||||
|
||||
if (bg->isArena() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
|
||||
sScriptMgr->OnBattlegroundDesertion(this, ARENA_DESERTION_TYPE_LEAVE_BG);
|
||||
|
||||
bg->RemovePlayerAtLeave(this);
|
||||
|
||||
// xinef: reset corpse reclaim time
|
||||
|
||||
@@ -1238,6 +1238,8 @@ public:
|
||||
return GetItemByPos(bag, slot);
|
||||
}
|
||||
[[nodiscard]] Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const;
|
||||
bool HasWeapon(WeaponAttackType type) const override { return GetWeaponForAttack(type, false); }
|
||||
bool HasWeaponForAttack(WeaponAttackType type) const override { return (Unit::HasWeaponForAttack(type) && GetWeaponForAttack(type, true)); }
|
||||
[[nodiscard]] Item* GetShield(bool useable = false) const;
|
||||
static uint8 GetAttackBySlot(uint8 slot); // MAX_ATTACK if not weapon slot
|
||||
std::vector<Item*>& GetItemUpdateQueue() { return m_itemUpdateQueue; }
|
||||
|
||||
@@ -195,7 +195,7 @@ void Player::Update(uint32 p_time)
|
||||
|
||||
// prevent base and off attack in same time, delay attack at
|
||||
// 0.2 sec
|
||||
if (haveOffhandWeapon())
|
||||
if (HasOffhandWeaponForAttack())
|
||||
if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
|
||||
setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
|
||||
|
||||
@@ -205,7 +205,7 @@ void Player::Update(uint32 p_time)
|
||||
}
|
||||
}
|
||||
|
||||
if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
|
||||
if (HasOffhandWeaponForAttack() && isAttackReady(OFF_ATTACK))
|
||||
{
|
||||
if (!IsWithinMeleeRange(victim))
|
||||
setAttackTimer(OFF_ATTACK, 100);
|
||||
|
||||
@@ -512,7 +512,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
||||
else
|
||||
{
|
||||
UpdateDamagePhysical(BASE_ATTACK);
|
||||
if (CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
|
||||
if (CanDualWield() && HasOffhandWeaponForAttack()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
|
||||
UpdateDamagePhysical(OFF_ATTACK);
|
||||
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_STATS) || IsClass(CLASS_PALADIN, CLASS_CONTEXT_STATS)) // mental quickness
|
||||
UpdateSpellDamageAndHealingBonus();
|
||||
@@ -567,7 +567,7 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
|
||||
float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
|
||||
float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
|
||||
|
||||
if (IsInFeralForm()) // check if player is druid and in cat or bear forms
|
||||
if (IsAttackSpeedOverridenShapeShift()) // forms with no override on attack speed use normal weapon damage
|
||||
{
|
||||
uint8 lvl = GetLevel();
|
||||
if (lvl > 60)
|
||||
@@ -1118,7 +1118,7 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
|
||||
break;
|
||||
}
|
||||
|
||||
if (attType == OFF_ATTACK && !haveOffhandWeapon())
|
||||
if (attType == OFF_ATTACK && !HasOffhandWeaponForAttack())
|
||||
{
|
||||
minDamage = 0.0f;
|
||||
maxDamage = 0.0f;
|
||||
@@ -1128,10 +1128,11 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
|
||||
float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
|
||||
float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
|
||||
|
||||
if (!CanUseAttackType(attType)) // disarm case
|
||||
// Disarm for creatures
|
||||
if (HasWeapon(attType) && !HasWeaponForAttack(attType))
|
||||
{
|
||||
weaponMinDamage = 0.0f;
|
||||
weaponMaxDamage = 0.0f;
|
||||
minDamage *= 0.5f;
|
||||
maxDamage *= 0.5f;
|
||||
}
|
||||
|
||||
float attackPower = GetTotalAttackPowerValue(attType);
|
||||
|
||||
@@ -1856,7 +1856,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
|
||||
float offtime = float(victim->getAttackTimer(OFF_ATTACK));
|
||||
float basetime = float(victim->getAttackTimer(BASE_ATTACK));
|
||||
// Reduce attack time
|
||||
if (victim->haveOffhandWeapon() && offtime < basetime)
|
||||
if (victim->HasOffhandWeaponForAttack() && offtime < basetime)
|
||||
{
|
||||
float percent20 = victim->GetAttackTime(OFF_ATTACK) * 0.20f;
|
||||
float percent60 = 3.0f * percent20;
|
||||
@@ -8430,7 +8430,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
if (dummySpell->SpellIconID == 2023)
|
||||
{
|
||||
// Must Dual Wield
|
||||
if (!procSpell || !haveOffhandWeapon())
|
||||
if (!procSpell || !HasOffhandWeaponForAttack())
|
||||
return false;
|
||||
// Chance as basepoints for dummy aura
|
||||
if (!roll_chance_i(triggerAmount))
|
||||
@@ -10365,9 +10365,9 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
|
||||
SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
|
||||
}
|
||||
|
||||
// delay offhand weapon attack to next attack time
|
||||
if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
|
||||
setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
|
||||
// delay offhand weapon attack by 50% of the base attack time
|
||||
if (HasOffhandWeaponForAttack() && isAttackReady(OFF_ATTACK))
|
||||
setAttackTimer(OFF_ATTACK, std::max(getAttackTimer(OFF_ATTACK), getAttackTimer(BASE_ATTACK) + int32(CalculatePct(GetFloatValue(UNIT_FIELD_BASEATTACKTIME), 50))));
|
||||
|
||||
if (meleeAttack)
|
||||
SendMeleeAttackStart(victim);
|
||||
@@ -13417,7 +13417,7 @@ float Unit::GetWeaponProcChance() const
|
||||
// (odd formula...)
|
||||
if (isAttackReady(BASE_ATTACK))
|
||||
return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
|
||||
else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
|
||||
else if (HasOffhandWeaponForAttack() && isAttackReady(OFF_ATTACK))
|
||||
return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
|
||||
return 0;
|
||||
}
|
||||
@@ -15423,7 +15423,7 @@ float Unit::GetTotalAttackPowerValue(WeaponAttackType attType, Unit* victim) con
|
||||
|
||||
float Unit::GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex /*= 0*/) const
|
||||
{
|
||||
if (attType == OFF_ATTACK && !haveOffhandWeapon())
|
||||
if (attType == OFF_ATTACK && !HasOffhandWeaponForAttack())
|
||||
return 0.0f;
|
||||
|
||||
return m_weaponDamage[attType][type][damageIndex];
|
||||
@@ -18984,7 +18984,7 @@ float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, i
|
||||
float missChance = victim->GetUnitMissChance(attType);
|
||||
|
||||
// Check if dual wielding, add additional miss penalty - when mainhand has on next swing spell, offhand doesnt suffer penalty
|
||||
if (!spellId && (attType != RANGED_ATTACK) && haveOffhandWeapon() && (!m_currentSpells[CURRENT_MELEE_SPELL] || !m_currentSpells[CURRENT_MELEE_SPELL]->IsNextMeleeSwingSpell()))
|
||||
if (!spellId && (attType != RANGED_ATTACK) && HasOffhandWeaponForAttack() && (!m_currentSpells[CURRENT_MELEE_SPELL] || !m_currentSpells[CURRENT_MELEE_SPELL]->IsNextMeleeSwingSpell()))
|
||||
{
|
||||
missChance += 19;
|
||||
}
|
||||
@@ -19498,6 +19498,16 @@ Unit* Unit::GetRedirectThreatTarget() const
|
||||
return _redirectThreatInfo.GetTargetGUID() ? ObjectAccessor::GetUnit(*this, _redirectThreatInfo.GetTargetGUID()) : nullptr;
|
||||
}
|
||||
|
||||
bool Unit::IsAttackSpeedOverridenShapeShift() const
|
||||
{
|
||||
// Mirroring clientside gameplay logic
|
||||
if (ShapeshiftForm form = GetShapeshiftForm())
|
||||
if (SpellShapeshiftFormEntry const* entry = sSpellShapeshiftFormStore.LookupEntry(form))
|
||||
return entry->attackSpeed > 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Unit::JumpTo(float speedXY, float speedZ, bool forward)
|
||||
{
|
||||
float angle = forward ? 0 : M_PI;
|
||||
@@ -21151,6 +21161,22 @@ void Unit::Whisper(std::string_view text, Language language, Player* target, boo
|
||||
target->SendDirectMessage(&data);
|
||||
}
|
||||
|
||||
uint32 Unit::GetVirtualItemId(uint32 slot) const
|
||||
{
|
||||
if (slot >= MAX_EQUIPMENT_ITEMS)
|
||||
return 0;
|
||||
|
||||
return GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + slot);
|
||||
}
|
||||
|
||||
void Unit::SetVirtualItem(uint32 slot, uint32 itemId)
|
||||
{
|
||||
if (slot >= MAX_EQUIPMENT_ITEMS)
|
||||
return;
|
||||
|
||||
SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + slot, itemId);
|
||||
}
|
||||
|
||||
void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target)
|
||||
{
|
||||
if (!sObjectMgr->GetBroadcastText(textId))
|
||||
|
||||
@@ -1053,6 +1053,17 @@ public:
|
||||
[[nodiscard]] float GetUnitMissChance(WeaponAttackType attType) const;
|
||||
float GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const;
|
||||
int32 GetMechanicResistChance(SpellInfo const* spell);
|
||||
|
||||
virtual bool HasWeapon(WeaponAttackType type) const = 0;
|
||||
inline bool HasMainhandWeapon() const { return HasWeapon(BASE_ATTACK); }
|
||||
inline bool HasOffhandWeapon() const { return HasWeapon(OFF_ATTACK); }
|
||||
inline bool HasRangedWeapon() const { return HasWeapon(RANGED_ATTACK); }
|
||||
|
||||
inline bool hasMainhandWeaponForAttack() const { return HasWeaponForAttack(BASE_ATTACK); }
|
||||
virtual bool HasWeaponForAttack(WeaponAttackType type) const { return CanUseAttackType(type); }
|
||||
inline bool HasMainhandWeaponForAttack() const { return HasWeaponForAttack(BASE_ATTACK); }
|
||||
inline bool HasOffhandWeaponForAttack() const { return HasWeaponForAttack(OFF_ATTACK); }
|
||||
inline bool HasRangedWeaponForAttack() const { return HasWeaponForAttack(RANGED_ATTACK); }
|
||||
[[nodiscard]] bool CanUseAttackType(uint8 attacktype) const
|
||||
{
|
||||
switch (attacktype)
|
||||
@@ -1063,8 +1074,9 @@ public:
|
||||
return !HasUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND);
|
||||
case RANGED_ATTACK:
|
||||
return !HasUnitFlag2(UNIT_FLAG2_DISARM_RANGED);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual uint32 GetShieldBlockValue() const = 0;
|
||||
@@ -1468,6 +1480,8 @@ public:
|
||||
SetByteValue(UNIT_FIELD_BYTES_2, 3, form);
|
||||
}
|
||||
|
||||
bool IsAttackSpeedOverridenShapeShift() const;
|
||||
|
||||
[[nodiscard]] bool IsInFeralForm() const
|
||||
{
|
||||
ShapeshiftForm form = GetShapeshiftForm();
|
||||
@@ -1762,6 +1776,9 @@ public:
|
||||
[[nodiscard]] float GetCollisionWidth() const override;
|
||||
[[nodiscard]] float GetCollisionRadius() const override;
|
||||
|
||||
uint32 GetVirtualItemId(uint32 slot) const;
|
||||
void SetVirtualItem(uint32 slot, uint32 itemId);
|
||||
|
||||
void ProcessPositionDataChanged(PositionFullTerrainStatus const& data) override;
|
||||
virtual void ProcessTerrainStatusUpdate();
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
#ifndef __ADDONHANDLER_H
|
||||
#define __ADDONHANDLER_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Config.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
class AddonHandler
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "DBCStores.h"
|
||||
#include "Item.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
@@ -580,6 +580,9 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
|
||||
|
||||
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_LEAVE_QUEUE);
|
||||
}
|
||||
|
||||
if (bg->isArena() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
|
||||
sScriptMgr->OnBattlegroundDesertion(_player, ARENA_DESERTION_TYPE_LEAVE_QUEUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
#include "StringConvert.h"
|
||||
#include "Tokenize.h"
|
||||
#include "Transport.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "CreatureAI.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "UpdateData.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
|
||||
@@ -20,10 +20,7 @@
|
||||
#include "GuildPackets.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "SocialMgr.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
void WorldSession::HandleGuildQueryOpcode(WorldPackets::Guild::QueryGuildInfo& query)
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include <cmath>
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "Pet.h"
|
||||
#include "PetPackets.h"
|
||||
#include "Player.h"
|
||||
#include "QueryHolder.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Totem.h"
|
||||
#include "TotemPackets.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "WaypointMovementGenerator.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
@@ -700,7 +700,9 @@ QuestItemList* Loot::FillQuestLoot(Player* player)
|
||||
}
|
||||
|
||||
// Player is not the loot owner, and loot owner still needs this quest item
|
||||
if (!item.freeforall && lootOwner != player && item.AllowedForPlayer(lootOwner, sourceWorldObjectGUID))
|
||||
if (!item.freeforall &&
|
||||
lootOwner && lootOwner != player &&
|
||||
item.AllowedForPlayer(lootOwner, sourceWorldObjectGUID))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -520,7 +520,7 @@ void MotionMaster::MoveLand(uint32 id, float x, float y, float z, float speed /*
|
||||
/**
|
||||
* @brief Use to move the unit from the ground to the air. Doesn't work with UNIT_FLAG_DISABLE_MOVE
|
||||
*/
|
||||
void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed /* = 0.0f*/)
|
||||
void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed /* = 0.0f*/, bool skipAnimation)
|
||||
{
|
||||
if (_owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
|
||||
return;
|
||||
@@ -538,7 +538,10 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed /* =
|
||||
init.SetVelocity(speed);
|
||||
}
|
||||
|
||||
init.SetAnimation(Movement::ToFly);
|
||||
if (!skipAnimation)
|
||||
{
|
||||
init.SetAnimation(Movement::ToFly);
|
||||
}
|
||||
init.Launch();
|
||||
Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE);
|
||||
}
|
||||
@@ -546,10 +549,10 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed /* =
|
||||
/**
|
||||
* @brief Use to move the unit from the air to the ground. Doesn't work with UNIT_FLAG_DISABLE_MOVE
|
||||
*/
|
||||
void MotionMaster::MoveTakeoff(uint32 id, float x, float y, float z, float speed /* = 0.0f*/)
|
||||
void MotionMaster::MoveTakeoff(uint32 id, float x, float y, float z, float speed /* = 0.0f*/, bool skipAnimation)
|
||||
{
|
||||
Position pos = {x, y, z, 0.0f};
|
||||
MoveTakeoff(id, pos, speed);
|
||||
MoveTakeoff(id, pos, speed, skipAnimation);
|
||||
}
|
||||
|
||||
void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
|
||||
|
||||
@@ -217,8 +217,8 @@ public:
|
||||
// These two movement types should only be used with creatures having landing/takeoff animations
|
||||
void MoveLand(uint32 id, Position const& pos, float speed = 0.0f);
|
||||
void MoveLand(uint32 id, float x, float y, float z, float speed = 0.0f); // pussywizard: added for easy calling by passing 3 floats x, y, z
|
||||
void MoveTakeoff(uint32 id, Position const& pos, float speed = 0.0f);
|
||||
void MoveTakeoff(uint32 id, float x, float y, float z, float speed = 0.0f); // pussywizard: added for easy calling by passing 3 floats x, y, z
|
||||
void MoveTakeoff(uint32 id, Position const& pos, float speed = 0.0f, bool skipAnimation = false);
|
||||
void MoveTakeoff(uint32 id, float x, float y, float z, float speed = 0.0f, bool skipAnimation = false); // pussywizard: added for easy calling by passing 3 floats x, y, z
|
||||
|
||||
void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, const Movement::PointsArray* path = nullptr, bool generatePath = false, float orientation = 0.0f, ObjectGuid targetGUID = ObjectGuid::Empty);
|
||||
void MoveCharge(PathGenerator const& path, float speed = SPEED_CHARGE, ObjectGuid targetGUID = ObjectGuid::Empty);
|
||||
|
||||
@@ -661,6 +661,9 @@ void WorldSession::LogoutPlayer(bool save)
|
||||
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_INVITE_LOGOUT);
|
||||
}
|
||||
|
||||
if (bgQueueTypeId >= BATTLEGROUND_QUEUE_2v2 && bgQueueTypeId < MAX_BATTLEGROUND_QUEUE_TYPES && _player->IsInvitedForBattlegroundQueueType(bgQueueTypeId))
|
||||
sScriptMgr->OnBattlegroundDesertion(_player, ARENA_DESERTION_TYPE_INVITE_LOGOUT);
|
||||
|
||||
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
|
||||
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(_player->GetGUID(), true);
|
||||
}
|
||||
|
||||
@@ -3160,6 +3160,13 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
|
||||
|
||||
if (m_spellAura)
|
||||
{
|
||||
// Prevent aura application if target is immuned
|
||||
if (m_targets.GetUnitTarget() && m_targets.GetUnitTarget()->IsImmunedToDamageOrSchool(m_spellAura->GetSpellInfo()))
|
||||
{
|
||||
m_spellAura->Remove();
|
||||
return SPELL_MISS_IMMUNE;
|
||||
}
|
||||
|
||||
// Set aura stack amount to desired value
|
||||
if (m_spellValue->AuraStackAmount > 1)
|
||||
{
|
||||
@@ -4061,7 +4068,7 @@ void Spell::_cast(bool skipCheck)
|
||||
{
|
||||
m_caster->resetAttackTimer(BASE_ATTACK);
|
||||
|
||||
if (m_caster->haveOffhandWeapon())
|
||||
if (m_caster->HasOffhandWeaponForAttack())
|
||||
{
|
||||
m_caster->resetAttackTimer(OFF_ATTACK);
|
||||
}
|
||||
|
||||
@@ -4837,6 +4837,19 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx5 |= SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL;
|
||||
});
|
||||
|
||||
// Fatal Attraction
|
||||
ApplySpellFix({ 40870 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->MaxAffectedTargets = 1;
|
||||
});
|
||||
|
||||
// Removing Dragonflayer Harpoon
|
||||
ApplySpellFix({ 42968 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->MaxAffectedTargets = 1;
|
||||
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(7);
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -309,6 +309,7 @@ enum WorldIntConfigs
|
||||
CONFIG_DEATH_SICKNESS_LEVEL,
|
||||
CONFIG_INSTANT_LOGOUT,
|
||||
CONFIG_DISABLE_BREATHING,
|
||||
CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS,
|
||||
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_SPAM_DELAY,
|
||||
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_TIMER,
|
||||
CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER,
|
||||
|
||||
@@ -1113,6 +1113,7 @@ void World::LoadConfigSettings(bool reload)
|
||||
_float_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfigMgr->GetOption<float>("ListenRange.TextEmote", 25.0f);
|
||||
_float_configs[CONFIG_LISTEN_RANGE_YELL] = sConfigMgr->GetOption<float>("ListenRange.Yell", 300.0f);
|
||||
|
||||
_int_configs[CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS] = sConfigMgr->GetOption<uint32>("Battleground.Override.LowLevels.MinPlayers", 0);
|
||||
_bool_configs[CONFIG_BATTLEGROUND_DISABLE_QUEST_SHARE_IN_BG] = sConfigMgr->GetOption<bool>("Battleground.DisableQuestShareInBG", false);
|
||||
_bool_configs[CONFIG_BATTLEGROUND_DISABLE_READY_CHECK_IN_BG] = sConfigMgr->GetOption<bool>("Battleground.DisableReadyCheckInBG", false);
|
||||
_bool_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfigMgr->GetOption<bool>("Battleground.CastDeserter", true);
|
||||
|
||||
Reference in New Issue
Block a user