This commit is contained in:
郑佩茹
2022-06-21 09:19:50 -06:00
125 changed files with 1505 additions and 851 deletions

View File

@@ -197,3 +197,65 @@ void Corpse::ResetGhostTime()
{
m_time = GameTime::GetGameTime().count();
}
void Corpse::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
{
if (!target)
return;
ByteBuffer fieldBuffer;
UpdateMask updateMask;
updateMask.SetCount(m_valuesCount);
uint32* flags = nullptr;
uint32 visibleFlag = GetUpdateFieldData(target, flags);
for (uint16 index = 0; index < m_valuesCount; ++index)
{
if (_fieldNotifyFlags & flags[index] || ((updateType == UPDATETYPE_VALUES ? _changesMask.GetBit(index) : m_uint32Values[index]) && (flags[index] & visibleFlag)))
{
updateMask.SetBit(index);
if (index == CORPSE_FIELD_BYTES_1 || index == CORPSE_FIELD_BYTES_2)
{
Player* owner = ObjectAccessor::GetPlayer(*this, GetOwnerGUID());
if (owner && owner != target && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && owner->IsInRaidWith(target) && owner->GetTeamId() != target->GetTeamId())
{
uint32 playerBytes = target->GetUInt32Value(PLAYER_BYTES);
uint32 playerBytes2 = target->GetUInt32Value(PLAYER_BYTES_2);
uint8 race = target->getRace();
uint8 skin = (uint8)(playerBytes);
uint8 face = (uint8)(playerBytes >> 8);
uint8 hairstyle = (uint8)(playerBytes >> 16);
uint8 haircolor = (uint8)(playerBytes >> 24);
uint8 facialhair = (uint8)(playerBytes2);
uint32 corpseBytes1 = ((0x00) | (race << 8) | (target->GetByteValue(PLAYER_BYTES_3, 0) << 16) | (skin << 24));
uint32 corpseBytes2 = ((face) | (hairstyle << 8) | (haircolor << 16) | (facialhair << 24));
if (index == CORPSE_FIELD_BYTES_1)
{
fieldBuffer << corpseBytes1;
}
else
{
fieldBuffer << corpseBytes2;
}
}
else
{
fieldBuffer << m_uint32Values[index];
}
}
else
{
fieldBuffer << m_uint32Values[index];
}
}
}
*data << uint8(updateMask.GetBlockCount());
updateMask.AppendToPacket(data);
data->append(fieldBuffer);
}

View File

@@ -54,6 +54,8 @@ public:
void AddToWorld() override;
void RemoveFromWorld() override;
void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const override;
bool Create(ObjectGuid::LowType guidlow);
bool Create(ObjectGuid::LowType guidlow, Player* owner);

View File

@@ -215,13 +215,13 @@ bool TemporaryThreatModifierEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
return true;
}
Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(), m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0), m_lootRecipientGroup(0),
Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(), m_groupLootTimer(0), lootingGroupLowGUID(0), m_lootRecipientGroup(0),
m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckTime(2500),
m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE),
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTimer(0),
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0)
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTarget(false), m_cannotReachTimer(0),
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
m_valuesCount = UNIT_END;
@@ -526,7 +526,7 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
uint32 previousHealth = GetHealth();
uint32 previousMaxHealth = GetMaxHealth();
uint32 previousPlayerDamageReq = m_PlayerDamageReq;
uint32 previousPlayerDamageReq = _playerDamageReq;
SelectLevel(changelevel);
if (previousHealth > 0)
@@ -535,11 +535,11 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
if (previousMaxHealth && previousMaxHealth > GetMaxHealth())
{
m_PlayerDamageReq = (uint32)(previousPlayerDamageReq * GetMaxHealth() / previousMaxHealth);
_playerDamageReq = (uint32)(previousPlayerDamageReq * GetMaxHealth() / previousMaxHealth);
}
else
{
m_PlayerDamageReq = previousPlayerDamageReq;
_playerDamageReq = previousPlayerDamageReq;
}
}
@@ -1831,14 +1831,14 @@ bool Creature::CanStartAttack(Unit const* who) const
return false;
// This set of checks is should be done only for creatures
if ((HasUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC) && who->GetTypeId() != TYPEID_PLAYER) || // flag is valid only for non player characters
(HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) && who->GetTypeId() == TYPEID_PLAYER)) // immune to PC and target is a player, return false
if ((IsImmuneToNPC() && who->GetTypeId() != TYPEID_PLAYER) || // flag is valid only for non player characters
(IsImmuneToPC() && who->GetTypeId() == TYPEID_PLAYER)) // immune to PC and target is a player, return false
{
return false;
}
if (Unit* owner = who->GetOwner())
if (owner->GetTypeId() == TYPEID_PLAYER && HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC)) // immune to PC and target has player owner
if (owner->GetTypeId() == TYPEID_PLAYER && IsImmuneToPC()) // immune to PC and target has player owner
return false;
// Do not attack non-combat pets
@@ -2369,7 +2369,7 @@ bool Creature::CanAssistTo(Unit const* u, Unit const* enemy, bool checkfaction /
if (IsCivilian())
return false;
if (HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_NPC))
if (HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE) || IsImmuneToNPC())
return false;
// skip fighting creature
@@ -3578,3 +3578,30 @@ void Creature::ModifyThreatPercentTemp(Unit* victim, int32 percent, Milliseconds
m_Events.AddEvent(pEvent, m_Events.CalculateTime(duration.count()));
}
}
bool Creature::IsDamageEnoughForLootingAndReward() const
{
return (m_creatureInfo->flags_extra & CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ) || (_playerDamageReq == 0 && _damagedByPlayer);
}
void Creature::LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer /*= true*/)
{
if (_playerDamageReq)
_playerDamageReq > unDamage ? _playerDamageReq -= unDamage : _playerDamageReq = 0;
if (!_damagedByPlayer)
{
_damagedByPlayer = damagedByPlayer;
}
}
void Creature::ResetPlayerDamageReq()
{
_playerDamageReq = GetHealth() / 2;
_damagedByPlayer = false;
}
uint32 Creature::GetPlayerDamageReq() const
{
return _playerDamageReq;
}

View File

@@ -340,14 +340,10 @@ public:
void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; }
[[nodiscard]] bool IsReputationGainDisabled() const { return DisableReputationGain; }
[[nodiscard]] bool IsDamageEnoughForLootingAndReward() const { return (m_creatureInfo->flags_extra & CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ) || (m_PlayerDamageReq == 0); }
void LowerPlayerDamageReq(uint32 unDamage)
{
if (m_PlayerDamageReq)
m_PlayerDamageReq > unDamage ? m_PlayerDamageReq -= unDamage : m_PlayerDamageReq = 0;
}
void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; }
uint32 m_PlayerDamageReq;
[[nodiscard]] bool IsDamageEnoughForLootingAndReward() const;
void LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer = true);
void ResetPlayerDamageReq();
[[nodiscard]] uint32 GetPlayerDamageReq() const;
[[nodiscard]] uint32 GetOriginalEntry() const { return m_originalEntry; }
void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }
@@ -468,6 +464,8 @@ private:
uint32 m_assistanceTimer;
uint32 _playerDamageReq;
bool _damagedByPlayer;
};
class AssistDelayEvent : public BasicEvent

View File

@@ -270,6 +270,11 @@ void CreatureGroup::MemberEvaded(Creature* member)
continue;
}
if (itr.second.HasGroupFlag(std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_DONT_RESPAWN_LEADER_ON_EVADE)) && pMember == m_leader)
{
continue;
}
pMember->Respawn();
}
}

View File

@@ -28,10 +28,11 @@ class CreatureGroup;
enum class GroupAIFlags : uint16
{
GROUP_AI_FLAG_MEMBER_ASSIST_LEADER = 0x001,
GROUP_AI_FLAG_LEADER_ASSIST_MEMBER = 0x002,
GROUP_AI_FLAG_EVADE_TOGETHER = 0x004,
GROUP_AI_FLAG_RESPAWN_ON_EVADE = 0x008,
GROUP_AI_FLAG_MEMBER_ASSIST_LEADER = 0x001,
GROUP_AI_FLAG_LEADER_ASSIST_MEMBER = 0x002,
GROUP_AI_FLAG_EVADE_TOGETHER = 0x004,
GROUP_AI_FLAG_RESPAWN_ON_EVADE = 0x008,
GROUP_AI_FLAG_DONT_RESPAWN_LEADER_ON_EVADE = 0x010,
//GROUP_AI_FLAG_UNK3 = 0x010,
//GROUP_AI_FLAG_UNK4 = 0x020,
//GROUP_AI_FLAG_UNK5 = 0x040,

View File

@@ -2089,7 +2089,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId)
trigger->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
// xinef: Remove Immunity flags
trigger->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
trigger->SetImmuneToNPC(false);
// xinef: set proper orientation, fixes cast against stealthed targets
if (target)
trigger->SetInFront(target);

View File

@@ -183,46 +183,64 @@ bool ItemCanGoIntoBag(ItemTemplate const* pProto, ItemTemplate const* pBagProto)
switch (pBagProto->Class)
{
case ITEM_CLASS_CONTAINER:
switch (pBagProto->SubClass)
{
if (pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER)
{
case ITEM_SUBCLASS_CONTAINER:
return true;
case ITEM_SUBCLASS_SOUL_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_SOUL_SHARDS))
return false;
return true;
case ITEM_SUBCLASS_HERB_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_HERBS))
return false;
return true;
case ITEM_SUBCLASS_ENCHANTING_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_ENCHANTING_SUPP))
return false;
return true;
case ITEM_SUBCLASS_MINING_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
return false;
return true;
case ITEM_SUBCLASS_ENGINEERING_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_ENGINEERING_SUPP))
return false;
return true;
case ITEM_SUBCLASS_GEM_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_GEMS))
return false;
return true;
case ITEM_SUBCLASS_LEATHERWORKING_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_LEATHERWORKING_SUPP))
return false;
return true;
case ITEM_SUBCLASS_INSCRIPTION_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_INSCRIPTION_SUPP))
return false;
return true;
default:
return false;
return true;
}
else
{
if (pProto->Class == ITEM_CLASS_CONTAINER)
{
return false;
}
switch (pBagProto->SubClass)
{
case ITEM_SUBCLASS_SOUL_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_SOUL_SHARDS))
return false;
return true;
case ITEM_SUBCLASS_HERB_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_HERBS))
return false;
return true;
case ITEM_SUBCLASS_ENCHANTING_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_ENCHANTING_SUPP))
return false;
return true;
case ITEM_SUBCLASS_MINING_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
return false;
return true;
case ITEM_SUBCLASS_ENGINEERING_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_ENGINEERING_SUPP))
return false;
return true;
case ITEM_SUBCLASS_GEM_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_GEMS))
return false;
return true;
case ITEM_SUBCLASS_LEATHERWORKING_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_LEATHERWORKING_SUPP))
return false;
return true;
case ITEM_SUBCLASS_INSCRIPTION_CONTAINER:
if (!(pProto->BagFamily & BAG_FAMILY_MASK_INSCRIPTION_SUPP))
return false;
return true;
default:
return false;
}
}
}
case ITEM_CLASS_QUIVER:
{
if (pProto->Class == ITEM_CLASS_QUIVER)
{
return false;
}
switch (pBagProto->SubClass)
{
case ITEM_SUBCLASS_QUIVER:
@@ -236,7 +254,9 @@ bool ItemCanGoIntoBag(ItemTemplate const* pProto, ItemTemplate const* pBagProto)
default:
return false;
}
}
}
return false;
}

View File

@@ -2643,12 +2643,13 @@ void Player::InitStatsForLevel(bool reapplyMods)
// cleanup unit flags (will be re-applied if need at aura load).
RemoveFlag(UNIT_FIELD_FLAGS,
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_ATTACKABLE_1 |
UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_LOOTING |
UNIT_FLAG_PET_IN_COMBAT | UNIT_FLAG_SILENCED | UNIT_FLAG_PACIFIED |
UNIT_FLAG_STUNNED | UNIT_FLAG_IN_COMBAT | UNIT_FLAG_DISARMED |
UNIT_FLAG_CONFUSED | UNIT_FLAG_FLEEING | UNIT_FLAG_NOT_SELECTABLE |
UNIT_FLAG_SKINNABLE | UNIT_FLAG_MOUNT | UNIT_FLAG_TAXI_FLIGHT );
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_ATTACKABLE_1 |
UNIT_FLAG_LOOTING | UNIT_FLAG_PET_IN_COMBAT | UNIT_FLAG_SILENCED |
UNIT_FLAG_PACIFIED | UNIT_FLAG_STUNNED | UNIT_FLAG_IN_COMBAT |
UNIT_FLAG_DISARMED | UNIT_FLAG_CONFUSED | UNIT_FLAG_FLEEING |
UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_SKINNABLE | UNIT_FLAG_MOUNT |
UNIT_FLAG_TAXI_FLIGHT);
SetImmuneToAll(false);
SetUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED); // must be set
SetUnitFlag2(UNIT_FLAG2_REGENERATE_POWER);// must be set

View File

@@ -1000,7 +1000,11 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
victim->ToCreature()->SetLootRecipient(attacker);
if (!attacker || attacker->IsControlledByPlayer() || attacker->IsCreatedByPlayer())
victim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage);
{
uint32 unDamage = health < damage ? health : damage;
bool damagedByPlayer = unDamage && attacker && attacker->m_movedByPlayer != nullptr;
victim->ToCreature()->LowerPlayerDamageReq(unDamage, damagedByPlayer);
}
}
if (health <= damage)
@@ -3867,7 +3871,11 @@ bool Unit::isInAccessiblePlaceFor(Creature const* c) const
return false;
}
if (IsInWater())
LiquidStatus liquidStatus = GetLiquidData().Status;
bool isInWater = (liquidStatus & MAP_LIQUID_STATUS_SWIMMING) != 0;
// In water or jumping in water
if (isInWater || (liquidStatus == LIQUID_MAP_ABOVE_WATER && (IsFalling() || (ToPlayer() && ToPlayer()->IsFalling()))))
{
return c->CanEnterWater();
}
@@ -13045,6 +13053,24 @@ void Unit::SetInCombatWith(Unit* enemy, uint32 duration)
SetInCombatState(false, enemy, duration);
}
void Unit::SetImmuneToPC(bool apply, bool keepCombat)
{
(void)keepCombat;
if (apply)
SetUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
else
RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
}
void Unit::SetImmuneToNPC(bool apply, bool keepCombat)
{
(void)keepCombat;
if (apply)
SetUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
else
RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
}
void Unit::CombatStart(Unit* victim, bool initialAggro)
{
// Xinef: Dont allow to start combat with triggers
@@ -13158,8 +13184,8 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy, uint32 duration)
return;
// xinef: if we somehow engage in combat (scripts, dunno) with player, remove this flag so he can fight back
if (GetTypeId() == TYPEID_UNIT && enemy && HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) && enemy->GetCharmerOrOwnerPlayerOrPlayerItself())
RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); // unit has engaged in combat, remove immunity so players can fight back
if (GetTypeId() == TYPEID_UNIT && enemy && IsImmuneToPC() && enemy->GetCharmerOrOwnerPlayerOrPlayerItself())
SetImmuneToPC(true); // unit has engaged in combat, remove immunity so players can fight back
if (IsInCombat())
return;
@@ -13225,7 +13251,7 @@ void Unit::ClearInCombat()
if (Creature* creature = ToCreature())
{
if (creature->GetCreatureTemplate() && creature->GetCreatureTemplate()->unit_flags & UNIT_FLAG_IMMUNE_TO_PC)
SetUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); // set immunity state to the one from db on evade
SetImmuneToPC(true); // set immunity state to the one from db on evade
ClearUnitState(UNIT_STATE_ATTACK_PLAYER);
if (HasDynamicFlag(UNIT_DYNFLAG_TAPPED))
@@ -13269,7 +13295,7 @@ bool Unit::isTargetableForAttack(bool checkFakeDeath, Unit const* byWho) const
if (HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
return false;
if (HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) && byWho && byWho->GetCharmerOrOwnerPlayerOrPlayerItself())
if (IsImmuneToPC() && byWho && byWho->GetCharmerOrOwnerPlayerOrPlayerItself())
return false;
if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster())
@@ -13324,11 +13350,11 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
}
// check flags
if (target->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_NON_ATTACKABLE_2)
|| (!HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && target->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC))
|| (!target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && HasUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC))
|| (HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && target->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC))
|| (!HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && target->IsImmuneToNPC())
|| (!target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && IsImmuneToNPC())
|| (HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && target->IsImmuneToPC())
// check if this is a world trigger cast - GOs are using world triggers to cast their spells, so we need to ignore their immunity flag here, this is a temp workaround, needs removal when go cast is implemented properly
|| ((GetEntry() != WORLD_TRIGGER && (!obj || !obj->isType(TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT))) && target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC)))
|| ((GetEntry() != WORLD_TRIGGER && (!obj || !obj->isType(TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT))) && target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && IsImmuneToPC()))
return false;
// CvC case - can attack each other only when one of them is hostile
@@ -13443,12 +13469,12 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
if (HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
{
if (target->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC))
if (target->IsImmuneToPC())
return false;
}
else
{
if (target->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC))
if (target->IsImmuneToNPC())
return false;
}
}
@@ -15737,9 +15763,9 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
else // For attacker
{
// Overpower on victim dodge
if (procExtra & PROC_EX_DODGE )
if (procExtra & PROC_EX_DODGE)
{
if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
if (getClass() == CLASS_WARRIOR)
{
AddComboPoints(target, 1);
StartReactiveTimer(REACTIVE_OVERPOWER);
@@ -16530,8 +16556,10 @@ void Unit::UpdateReactives(uint32 p_time)
ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
break;
case REACTIVE_OVERPOWER:
if (getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER)
if (getClass() == CLASS_WARRIOR)
{
ClearComboPoints();
}
break;
case REACTIVE_WOLVERINE_BITE:
if (IsHunterPet())

View File

@@ -1648,6 +1648,13 @@ public:
[[nodiscard]] bool IsInFlight() const { return HasUnitState(UNIT_STATE_IN_FLIGHT); }
void SetImmuneToAll(bool apply, bool keepCombat = false) { SetImmuneToPC(apply, keepCombat); SetImmuneToNPC(apply, keepCombat); }
bool IsImmuneToAll() const { return IsImmuneToPC() && IsImmuneToNPC(); }
void SetImmuneToPC(bool apply, bool keepCombat = false);
bool IsImmuneToPC() const { return HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); }
void SetImmuneToNPC(bool apply, bool keepCombat = false);
bool IsImmuneToNPC() const { return HasUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC); }
bool IsEngaged() const { return IsInCombat(); }
bool IsEngagedBy(Unit const* who) const { return IsInCombatWith(who); }