Merge branch 'master' into Playerbot

# Conflicts:
#	src/server/game/Guilds/Guild.cpp
This commit is contained in:
郑佩茹
2023-04-03 07:52:56 -06:00
64 changed files with 944 additions and 216 deletions
@@ -3905,7 +3905,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
if (!me || !me->IsEngaged())
return;
ObjectVector targets;
Unit* unitTarget = nullptr;
switch (e.GetTargetType())
{
case SMART_TARGET_CREATURE_RANGE:
@@ -3916,8 +3916,8 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
case SMART_TARGET_PLAYER_RANGE:
case SMART_TARGET_PLAYER_DISTANCE:
{
if (targets.empty())
return;
ObjectVector targets;
GetTargets(targets, e);
for (WorldObject* target : targets)
{
if (IsUnit(target) && me->IsFriendlyTo(target->ToUnit()) && target->ToUnit()->IsAlive() && target->ToUnit()->IsInCombat())
@@ -3928,7 +3928,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
continue;
}
target = target->ToUnit();
unitTarget = target->ToUnit();
break;
}
}
@@ -3937,16 +3937,16 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
}
case SMART_TARGET_SELF:
case SMART_TARGET_ACTION_INVOKER:
DoSelectLowestHpPercentFriendly((float)e.event.friendlyHealthPct.radius, e.event.friendlyHealthPct.minHpPct, e.event.friendlyHealthPct.maxHpPct);
unitTarget = DoSelectLowestHpPercentFriendly((float)e.event.friendlyHealthPct.radius, e.event.friendlyHealthPct.minHpPct, e.event.friendlyHealthPct.maxHpPct);
break;
default:
return;
}
if (targets.empty())
if (!unitTarget)
return;
ProcessTimedAction(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax);
ProcessTimedAction(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax, unitTarget);
break;
}
case SMART_EVENT_DISTANCE_CREATURE:
+23 -1
View File
@@ -2101,34 +2101,52 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= nullptr*/)
{
// not need after this call
if (owner->ToPlayer()->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS))
{
owner->ToPlayer()->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS, true);
}
// reset for online
if (onlinePet)
{
onlinePet->resetTalents();
}
PetStable* petStable = owner->GetPetStable();
if (!petStable)
{
return;
}
std::unordered_set<uint32> petIds;
if (petStable->CurrentPet)
{
petIds.insert(petStable->CurrentPet->PetNumber);
}
for (Optional<PetStable::PetInfo> const& stabledPet : petStable->StabledPets)
{
if (stabledPet)
{
petIds.insert(stabledPet->PetNumber);
}
}
for (PetStable::PetInfo const& unslottedPet : petStable->UnslottedPets)
{
petIds.insert(unslottedPet.PetNumber);
}
// now need only reset for offline pets (all pets except online case)
if (onlinePet)
{
petIds.erase(onlinePet->GetCharmInfo()->GetPetNumber());
}
// no offline pets
if (!petIds.empty())
if (petIds.empty())
{
return;
}
bool need_comma = false;
std::ostringstream ss;
@@ -2137,7 +2155,9 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= nullptr*/)
for (uint32 id : petIds)
{
if (need_comma)
{
ss << ',';
}
ss << id;
@@ -2150,7 +2170,9 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= nullptr*/)
for (uint32 spell : sPetTalentSpells)
{
if (need_comma)
{
ss << ',';
}
ss << spell;
+18 -5
View File
@@ -1462,7 +1462,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
else
{
if (getClass() == CLASS_DEATH_KNIGHT && GetMapId() == 609 && !IsGameMaster() && !HasSpell(50977))
{
SendTransferAborted(mapid, TRANSFER_ABORT_UNIQUE_MESSAGE, 1);
return false;
}
// far teleport to another map
Map* oldmap = IsInWorld() ? GetMap() : nullptr;
@@ -6824,8 +6827,10 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
if (extraDPS)
{
float average = extraDPS * proto->Delay / 1000.0f;
minDamage = 0.7f * average;
maxDamage = 1.3f * average;
float mod = ssv->IsTwoHand(proto->ScalingStatValue) ? 0.2f : 0.3f;
minDamage = (1.0f - mod) * average;
maxDamage = (1.0f + mod) * average;
}
}
@@ -7220,6 +7225,15 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
continue;
}
if (entry && (entry->attributeMask & ENCHANT_PROC_ATTR_EXCLUSIVE) != 0)
{
Unit* checkTarget = spellInfo->IsPositive() ? this : target;
if (checkTarget->HasAura(spellInfo->Id, GetGUID()))
{
continue;
}
}
float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance();
if (entry)
@@ -11579,7 +11593,6 @@ void Player::SendInitialPacketsAfterAddToMap()
SendMessageToSet(&data2, true);
}
GetAurasForTarget(this);
SendEnchantmentDurations(); // must be after add to map
SendItemDurations(); // must be after add to map
SendQuestGiverStatusMultiple();
@@ -11960,9 +11973,9 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value)
}
}
void Player::GetAurasForTarget(Unit* target) // pussywizard: contact before changing ANYTHING!
void Player::GetAurasForTarget(Unit* target, bool force /*= false*/)
{
if (!target/* || target->GetVisibleAuras()->empty()*/) // speedup things
if (!target || (!force && target->GetVisibleAuras()->empty())) // speedup things
return;
/*! Blizz sends certain movement packets sometimes even before CreateObject
+1 -1
View File
@@ -2183,7 +2183,7 @@ public:
void SendBGWeekendWorldStates();
void SendBattlefieldWorldStates();
void GetAurasForTarget(Unit* target);
void GetAurasForTarget(Unit* target, bool force = false);
PlayerMenu* PlayerTalkClass;
std::vector<ItemSetEffect*> ItemSetEff;
+31 -14
View File
@@ -3822,6 +3822,8 @@ void Unit::_UpdateSpells(uint32 time)
{
if (i->second->IsExpired())
RemoveOwnedAura(i, AURA_REMOVE_BY_EXPIRE);
else if (i->second->GetSpellInfo()->IsChanneled() && i->second->GetCasterGUID() != GetGUID() && !ObjectAccessor::GetWorldObject(*this, i->second->GetCasterGUID()))
RemoveOwnedAura(i, AURA_REMOVE_BY_CANCEL); // remove channeled auras when caster is not on the same map
else
++i;
}
@@ -6498,11 +6500,12 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
}
//victim may be nullptr
bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc /*= nullptr*/)
bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, ProcEventInfo const& eventInfo)
{
SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
uint32 effIndex = triggeredByAura->GetEffIndex();
int32 triggerAmount = triggeredByAura->GetAmount();
Spell const* spellProc = eventInfo.GetProcSpell();
Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : nullptr;
@@ -7864,12 +7867,22 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
if (!procSpell || !procSpell->IsPositive())
return false;
// heal amount
basepoints0 = int32(CalculatePct(std::min(damage, GetMaxHealth() - GetHealth()), triggerAmount));
target = this;
HealInfo const* healInfo = eventInfo.GetHealInfo();
if (!healInfo)
{
return false;
}
if (basepoints0)
triggered_spell_id = 31786;
uint32 effectiveHeal = healInfo->GetEffectiveHeal();
if (effectiveHeal)
{
// heal amount
basepoints0 = int32(CalculatePct(effectiveHeal, triggerAmount));
target = this;
if (basepoints0)
triggered_spell_id = 31786;
}
break;
}
// Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
@@ -11202,16 +11215,18 @@ void Unit::UnsummonAllTotems(bool onDeath /*= false*/)
}
}
void Unit::SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical)
void Unit::SendHealSpellLog(HealInfo const& healInfo, bool critical)
{
uint32 overheal = healInfo.GetHeal() - healInfo.GetEffectiveHeal();
// we guess size
WorldPacket data(SMSG_SPELLHEALLOG, (8 + 8 + 4 + 4 + 4 + 4 + 1 + 1));
data << victim->GetPackGUID();
data << healInfo.GetTarget()->GetPackGUID();
data << GetPackGUID();
data << uint32(SpellID);
data << uint32(Damage);
data << uint32(OverHeal);
data << uint32(Absorb); // Absorb amount
data << uint32(healInfo.GetSpellInfo()->Id);
data << uint32(healInfo.GetHeal());
data << uint32(overheal);
data << uint32(healInfo.GetAbsorb()); // Absorb amount
data << uint8(critical ? 1 : 0);
data << uint8(0); // unused
SendMessageToSet(&data, true);
@@ -11227,7 +11242,9 @@ int32 Unit::HealBySpell(HealInfo& healInfo, bool critical)
CalcHealAbsorb(healInfo);
int32 gain = Unit::DealHeal(healInfo.GetHealer(), healInfo.GetTarget(), healInfo.GetHeal());
SendHealSpellLog(healInfo.GetTarget(), healInfo.GetSpellInfo()->Id, healInfo.GetHeal(), uint32(healInfo.GetHeal() - gain), healInfo.GetAbsorb(), critical);
healInfo.SetEffectiveHeal(gain);
SendHealSpellLog(healInfo, critical);
return gain;
}
@@ -16555,7 +16572,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
case SPELL_AURA_DUMMY:
{
LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} dummy aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procSpell))
if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, eventInfo))
takeCharges = true;
break;
}
+14 -2
View File
@@ -806,6 +806,7 @@ private:
Unit* const m_healer;
Unit* const m_target;
uint32 m_heal;
uint32 m_effectiveHeal;
uint32 m_absorb;
SpellInfo const* const m_spellInfo;
SpellSchoolMask const m_schoolMask;
@@ -814,12 +815,17 @@ public:
: m_healer(_healer), m_target(_target), m_heal(_heal), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask)
{
m_absorb = 0;
m_effectiveHeal = 0;
}
void AbsorbHeal(uint32 amount)
{
amount = std::min(amount, GetHeal());
m_absorb += amount;
m_heal -= amount;
amount = std::min(amount, GetEffectiveHeal());
m_effectiveHeal -= amount;
}
void SetHeal(uint32 amount)
@@ -827,9 +833,15 @@ public:
m_heal = amount;
}
void SetEffectiveHeal(uint32 amount)
{
m_effectiveHeal = amount;
}
[[nodiscard]] Unit* GetHealer() const { return m_healer; }
[[nodiscard]] Unit* GetTarget() const { return m_target; }
[[nodiscard]] uint32 GetHeal() const { return m_heal; }
[[nodiscard]] uint32 GetEffectiveHeal() const { return m_effectiveHeal; }
[[nodiscard]] uint32 GetAbsorb() const { return m_absorb; }
[[nodiscard]] SpellInfo const* GetSpellInfo() const { return m_spellInfo; };
[[nodiscard]] SpellSchoolMask GetSchoolMask() const { return m_schoolMask; };
@@ -1724,7 +1736,7 @@ public:
[[nodiscard]] virtual bool IsUnderWater() const;
bool isInAccessiblePlaceFor(Creature const* c) const;
void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false);
void SendHealSpellLog(HealInfo const& healInfo, bool critical = false);
int32 HealBySpell(HealInfo& healInfo, bool critical = false);
void SendEnergizeSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype);
void EnergizeBySpell(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype);
@@ -2551,7 +2563,7 @@ protected:
private:
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc = nullptr);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, ProcEventInfo const& eventInfo);
bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled);
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo);
bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown);
+1 -1
View File
@@ -39,7 +39,7 @@ class ObjectGuid;
#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2)
#define MIN_GRID_DELAY (MINUTE*IN_MILLISECONDS)
#define MIN_MAP_UPDATE_DELAY 10
#define MIN_MAP_UPDATE_DELAY 1
#define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS)
+2
View File
@@ -1201,6 +1201,7 @@ void Guild::HandleRoster(WorldSession* session)
{
WorldPackets::Guild::GuildRoster roster;
roster.RankData.reserve(m_ranks.size());
for (RankInfo const& rank : m_ranks)
{
WorldPackets::Guild::GuildRankData& rankData = roster.RankData.emplace_back();
@@ -1215,6 +1216,7 @@ void Guild::HandleRoster(WorldSession* session)
}
bool sendOfficerNote = HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE);
roster.MemberData.reserve(m_members.size());
for (auto const& [guid, member] : m_members)
{
WorldPackets::Guild::GuildRosterMemberData& memberData = roster.MemberData.emplace_back();
+7 -6
View File
@@ -784,14 +784,15 @@ void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket& recvData)
void WorldSession::HandleRaidReadyCheckFinishedOpcode(WorldPacket& /*recvData*/)
{
//Group* group = GetPlayer()->GetGroup();
//if (!group)
// return;
Group* group = GetPlayer()->GetGroup();
if (!group)
return;
//if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
// return;
if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
return;
// Is any reaction need?
WorldPacket data(MSG_RAID_READY_CHECK_FINISHED);
group->BroadcastPacket(&data, true, -1);
}
void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data)
+13 -2
View File
@@ -2525,6 +2525,7 @@ void Map::SendInitSelf(Player* player)
{
LOG_DEBUG("maps", "Creating player data for himself {}", player->GetGUID().ToString());
WorldPacket packet;
UpdateData data;
// attach to player data current transport data
@@ -2534,15 +2535,25 @@ void Map::SendInitSelf(Player* player)
// build data for self presence in world at own client (one time for map)
player->BuildCreateUpdateBlockForPlayer(&data, player);
// build and send self update packet before sending to player his own auras
data.BuildPacket(&packet);
player->SendDirectMessage(&packet);
// send to player his own auras (this is needed here for timely initialization of some fields on client)
player->GetAurasForTarget(player, true);
// clean buffers for further work
packet.clear();
data.Clear();
// build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
if (Transport* transport = player->GetTransport())
for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
if (player != (*itr) && player->HaveAtClient(*itr))
(*itr)->BuildCreateUpdateBlockForPlayer(&data, player);
WorldPacket packet;
data.BuildPacket(&packet);
player->GetSession()->SendPacket(&packet);
player->SendDirectMessage(&packet);
}
void Map::SendInitTransports(Player* player)
@@ -6626,8 +6626,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
HealInfo healInfo(caster, target, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
Unit::CalcHealAbsorb(healInfo);
int32 gain = Unit::DealHeal(caster, target, healInfo.GetHeal());
healInfo.SetEffectiveHeal(gain);
SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - gain, healInfo.GetAbsorb(), 0, 0.0f, crit);
SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
if (caster)
@@ -4374,7 +4374,8 @@ void SpellMgr::LoadSpellInfoCorrections()
});
// Judgement (Paladin T2 8P Bonus)
ApplySpellFix({ 23591 }, [](SpellInfo* spellInfo)
// Battlegear of Eternal Justice
ApplySpellFix({ 23591, 26135 }, [](SpellInfo* spellInfo)
{
spellInfo->ProcFlags = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS;
});
+3 -2
View File
@@ -2211,8 +2211,8 @@ void SpellMgr::LoadSpellEnchantProcData()
mSpellEnchantProcEventMap.clear(); // need for reload case
// 0 1 2 3
QueryResult result = WorldDatabase.Query("SELECT entry, customChance, PPMChance, procEx FROM spell_enchant_proc_data");
// 0 1 2 3 4
QueryResult result = WorldDatabase.Query("SELECT entry, customChance, PPMChance, procEx, attributeMask FROM spell_enchant_proc_data");
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 spell enchant proc event conditions. DB table `spell_enchant_proc_data` is empty.");
@@ -2239,6 +2239,7 @@ void SpellMgr::LoadSpellEnchantProcData()
spe.customChance = fields[1].Get<uint32>();
spe.PPMChance = fields[2].Get<float>();
spe.procEx = fields[3].Get<uint32>();
spe.attributeMask = fields[4].Get<uint32>();
mSpellEnchantProcEventMap[enchantId] = spe;
+6
View File
@@ -304,11 +304,17 @@ struct SpellProcEntry
typedef std::unordered_map<uint32, SpellProcEntry> SpellProcMap;
enum EnchantProcAttributes
{
ENCHANT_PROC_ATTR_EXCLUSIVE = 0x1 // Only one instance of that effect can be active
};
struct SpellEnchantProcEntry
{
uint32 customChance;
float PPMChance;
uint32 procEx;
uint32 attributeMask;
};
typedef std::unordered_map<uint32, SpellEnchantProcEntry> SpellEnchantProcEventMap;
+1 -1
View File
@@ -667,7 +667,7 @@ void World::LoadConfigSettings(bool reload)
_int_configs[CONFIG_MIN_LEVEL_STAT_SAVE] = 0;
}
_int_configs[CONFIG_INTERVAL_MAPUPDATE] = sConfigMgr->GetOption<int32>("MapUpdateInterval", 100);
_int_configs[CONFIG_INTERVAL_MAPUPDATE] = sConfigMgr->GetOption<int32>("MapUpdateInterval", 10);
if (_int_configs[CONFIG_INTERVAL_MAPUPDATE] < MIN_MAP_UPDATE_DELAY)
{
LOG_ERROR("server.loading", "MapUpdateInterval ({}) must be greater {}. Use this minimal value.", _int_configs[CONFIG_INTERVAL_MAPUPDATE], MIN_MAP_UPDATE_DELAY);
-2
View File
@@ -141,8 +141,6 @@ enum WorldStates
WS_DAILY_CALENDAR_DELETION_OLD_EVENTS_TIME = 20008 // Next daily calendar deletions of old events time
};
#define WORLD_SLEEP_CONST 10
// xinef: petitions storage
struct PetitionData
{