Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-06-14 21:33:35 +08:00
138 changed files with 3510 additions and 1281 deletions

View File

@@ -2591,7 +2591,7 @@ bool Creature::_IsTargetAcceptable(Unit const* target) const
void Creature::UpdateMoveInLineOfSightState()
{
// xinef: pets, guardians and units with scripts / smartAI should be skipped
if (IsPet() || HasUnitTypeMask(UNIT_MASK_MINION | UNIT_MASK_SUMMON | UNIT_MASK_GUARDIAN | UNIT_MASK_CONTROLABLE_GUARDIAN) ||
if (IsPet() || HasUnitTypeMask(UNIT_MASK_MINION | UNIT_MASK_SUMMON | UNIT_MASK_GUARDIAN | UNIT_MASK_CONTROLLABLE_GUARDIAN) ||
GetScriptId() || GetAIName() == "SmartAI")
{
m_moveInLineOfSightStrictlyDisabled = false;
@@ -3735,7 +3735,7 @@ uint8 Creature::GetLeashTimer() const
{ // Based on testing on Classic, seems to range from ~11s for low level mobs (1-5) to ~16s for high level mobs (70+)
uint8 timerOffset = 11;
uint8 timerModifier = uint8(GetLevel() / 10) - 2;
uint8 timerModifier = uint8(GetCreatureTemplate()->minlevel / 10) - 2;
// Formula is likely not quite correct, but better than flat timer
return std::max<uint8>(timerOffset, timerOffset + timerModifier);

View File

@@ -422,7 +422,7 @@ Guardian::Guardian(SummonPropertiesEntry const* properties, ObjectGuid owner, bo
m_unitTypeMask |= UNIT_MASK_GUARDIAN;
if (properties && (properties->Type == SUMMON_TYPE_PET || properties->Category == SUMMON_CATEGORY_PET))
{
m_unitTypeMask |= UNIT_MASK_CONTROLABLE_GUARDIAN;
m_unitTypeMask |= UNIT_MASK_CONTROLLABLE_GUARDIAN;
InitCharmInfo();
}
}
@@ -435,7 +435,7 @@ void Guardian::InitStats(uint32 duration)
{
InitStatsForLevel(m_owner->GetLevel());
if (m_owner->IsPlayer() && HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
if (m_owner->IsPlayer() && HasUnitTypeMask(UNIT_MASK_CONTROLLABLE_GUARDIAN))
m_charmInfo->InitCharmCreateSpells();
}

View File

@@ -60,9 +60,9 @@ Pet::Pet(Player* owner, PetType type) : Guardian(nullptr, owner ? owner->GetGUID
if (type == HUNTER_PET)
m_unitTypeMask |= UNIT_MASK_HUNTER_PET;
if (!(m_unitTypeMask & UNIT_MASK_CONTROLABLE_GUARDIAN))
if (!(m_unitTypeMask & UNIT_MASK_CONTROLLABLE_GUARDIAN))
{
m_unitTypeMask |= UNIT_MASK_CONTROLABLE_GUARDIAN;
m_unitTypeMask |= UNIT_MASK_CONTROLLABLE_GUARDIAN;
InitCharmInfo();
}

View File

@@ -393,7 +393,6 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
m_achievementMgr = new AchievementMgr(this);
m_reputationMgr = new ReputationMgr(this);
// Ours
m_NeedToSaveGlyphs = false;
m_MountBlockId = 0;
m_realDodge = 0.0f;
@@ -7188,8 +7187,7 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply,
LOG_DEBUG("entities.player", "WORLD: cast {} Equip spellId - {}", (item ? "item" : "itemset"), spellInfo->Id);
//Ignore spellInfo->DurationEntry, cast with -1 duration
CastCustomSpell(spellInfo->Id, SPELLVALUE_AURA_DURATION, -1, this, true, item);
CastSpell(this, spellInfo, true, item);
}
else
{

View File

@@ -2570,7 +2570,6 @@ public:
[[nodiscard]] bool CanFly() const override { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); }
[[nodiscard]] bool CanEnterWater() const override { return true; }
// OURS
// saving
void AdditionalSavingAddMask(uint8 mask) { m_additionalSaveTimer = 2000; m_additionalSaveMask |= mask; }
// arena spectator

View File

@@ -424,7 +424,7 @@ void Unit::Update(uint32 p_time)
SendThreatListUpdate();
// update combat timer only for players and pets (only pets with PetAI)
if (IsInCombat() && (IsPlayer() || ((IsPet() || HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN)) && IsControlledByPlayer())))
if (IsInCombat() && (IsPlayer() || ((IsPet() || HasUnitTypeMask(UNIT_MASK_CONTROLLABLE_GUARDIAN)) && IsControlledByPlayer())))
{
// Check UNIT_STATE_MELEE_ATTACKING or UNIT_STATE_CHASE (without UNIT_STATE_FOLLOW in this case) so pets can reach far away
// targets without stopping half way there and running off.
@@ -10793,7 +10793,7 @@ void Unit::SetMinion(Minion* minion, bool apply)
}
}
if (minion->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
if (minion->HasUnitTypeMask(UNIT_MASK_CONTROLLABLE_GUARDIAN))
{
AddGuidValue(UNIT_FIELD_SUMMON, minion->GetGUID());
}
@@ -10888,7 +10888,7 @@ void Unit::SetMinion(Minion* minion, bool apply)
}
ASSERT((*itr)->IsCreature());
if (!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
if (!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLLABLE_GUARDIAN))
continue;
if (AddGuidValue(UNIT_FIELD_SUMMON, (*itr)->GetGUID()))
@@ -11703,7 +11703,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
int32 DoneTotal = 0;
float DoneTotalMod = TotalMod ? TotalMod : SpellPctDamageModsDone(victim, spellProto, damagetype);
// Config : RATE_CREATURE_X_SPELLDAMAGE & Do Not Modify Pet/Guardian/Mind Controled Damage
// Config : RATE_CREATURE_X_SPELLDAMAGE & Do Not Modify Pet/Guardian/Mind Controlled Damage
if (IsCreature() && (!ToCreature()->IsPet() || !ToCreature()->IsGuardian() || !ToCreature()->IsControlledByPlayer()))
DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->rank);
@@ -13520,7 +13520,7 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spe
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_PROC_PER_MINUTE, PPM);
return std::floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
return (WeaponSpeed * PPM) / 600.0f; // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
}
void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
@@ -14698,7 +14698,7 @@ bool Unit::CanHaveThreatList(bool skipAliveCheck) const
return false;
// summons can not have a threat list, unless they are controlled by a creature
if (HasUnitTypeMask(UNIT_MASK_MINION | UNIT_MASK_GUARDIAN | UNIT_MASK_CONTROLABLE_GUARDIAN) && ((Pet*)this)->GetOwnerGUID().IsPlayer())
if (HasUnitTypeMask(UNIT_MASK_MINION | UNIT_MASK_GUARDIAN | UNIT_MASK_CONTROLLABLE_GUARDIAN) && ((Pet*)this)->GetOwnerGUID().IsPlayer())
return false;
return true;
@@ -14854,7 +14854,7 @@ Unit* Creature::SelectVictim()
// it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
// Note: creature does not have targeted movement generator but has attacker in this case
for (AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr)
if ((*itr) && CanCreatureAttack(*itr) && !(*itr)->IsPlayer() && !(*itr)->ToCreature()->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
if ((*itr) && CanCreatureAttack(*itr) && !(*itr)->IsPlayer() && !(*itr)->ToCreature()->HasUnitTypeMask(UNIT_MASK_CONTROLLABLE_GUARDIAN))
return nullptr;
if (GetVehicle())
@@ -17572,16 +17572,30 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackTyp
// If PPM exist calculate chance from PPM
if (spellProcEvent && spellProcEvent->ppmRate != 0)
{
uint32 attackSpeed = 0;
Unit* attacker = nullptr;
if (!isVictim)
{
uint32 WeaponSpeed = GetAttackTime(attType);
chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto);
}
attacker = this;
else if (victim)
attacker = victim;
if (attacker)
{
uint32 WeaponSpeed = victim->GetAttackTime(attType);
chance = victim->GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto);
if (!procSpell || procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE || procSpell->IsRangedWeaponSpell())
{
attackSpeed = attacker->GetAttackTime(attType);
}
else //spells user their casttime for ppm calculations
{
if (procSpell->CastTimeEntry)
attackSpeed = procSpell->CastTimeEntry->CastTime;
//instants and fast spells use 1.5s castspeed
if (attackSpeed < 1500)
attackSpeed = 1500;
}
}
chance = GetPPMProcChance(attackSpeed, spellProcEvent->ppmRate, spellProto);
}
// Custom chances
@@ -20011,11 +20025,11 @@ void Unit::StopAttackingInvalidTarget()
attacker->ToPlayer()->SendAttackSwingCancelAttack();
}
for (Unit* controled : attacker->m_Controlled)
for (Unit* controlled : attacker->m_Controlled)
{
if (controled->GetVictim() == this && !controled->IsValidAttackTarget(this))
if (controlled->GetVictim() == this && !controlled->IsValidAttackTarget(this))
{
controled->AttackStop();
controlled->AttackStop();
}
}

View File

@@ -743,7 +743,7 @@ public:
// Unit type methods
[[nodiscard]] bool IsSummon() const { return m_unitTypeMask & UNIT_MASK_SUMMON; }
[[nodiscard]] bool IsGuardian() const { return m_unitTypeMask & UNIT_MASK_GUARDIAN; }
[[nodiscard]] bool IsControllableGuardian() const { return m_unitTypeMask & UNIT_MASK_CONTROLABLE_GUARDIAN; }
[[nodiscard]] bool IsControllableGuardian() const { return m_unitTypeMask & UNIT_MASK_CONTROLLABLE_GUARDIAN; }
[[nodiscard]] bool IsPet() const { return m_unitTypeMask & UNIT_MASK_PET; }
[[nodiscard]] bool IsHunterPet() const { return m_unitTypeMask & UNIT_MASK_HUNTER_PET; }
[[nodiscard]] bool IsTotem() const { return m_unitTypeMask & UNIT_MASK_TOTEM; }

View File

@@ -161,7 +161,7 @@ enum UnitTypeMask
UNIT_MASK_VEHICLE = 0x00000020,
UNIT_MASK_PUPPET = 0x00000040,
UNIT_MASK_HUNTER_PET = 0x00000080,
UNIT_MASK_CONTROLABLE_GUARDIAN = 0x00000100,
UNIT_MASK_CONTROLLABLE_GUARDIAN = 0x00000100,
UNIT_MASK_ACCESSORY = 0x00000200
};