Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-09-19 09:23:59 -06:00
committed by GitHub
33 changed files with 677 additions and 148 deletions

View File

@@ -4059,6 +4059,13 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
}
}
// Delay flee for assist event if casting
if (e.GetActionType() == SMART_ACTION_FLEE_FOR_ASSIST && me && me->HasUnitState(UNIT_STATE_CASTING))
{
e.timer = 1;
return;
}
e.active = true;//activate events with cooldown
switch (e.GetEventType())//process ONLY timed events
{

View File

@@ -1745,11 +1745,13 @@ void GameObject::Use(Unit* user)
LOG_DEBUG("entities.gameobject", "Fishing check (skill: {} zone min skill: {} chance {} roll: {}", skill, zone_skill, chance, roll);
if (sScriptMgr->OnUpdateFishingSkill(player, skill, zone_skill, chance, roll))
{
player->UpdateFishingSkill();
}
// but you will likely cause junk in areas that require a high fishing skill (not yet implemented)
if (chance >= roll)
{
player->UpdateFishingSkill();
//TODO: I do not understand this hack. Need some explanation.
// prevent removing GO at spell cancel
RemoveFromOwner();

View File

@@ -169,6 +169,7 @@ ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget,
: _actor(actor), _actionTarget(actionTarget), _procTarget(procTarget), _typeMask(typeMask), _spellTypeMask(spellTypeMask), _spellPhaseMask(spellPhaseMask),
_hitMask(hitMask), _spell(spell), _damageInfo(damageInfo), _healInfo(healInfo), _triggeredByAuraSpell(triggeredByAuraSpell), _procAuraEffectIndex(procAuraEffectIndex)
{
_chance.reset();
}
SpellInfo const* ProcEventInfo::GetSpellInfo() const
@@ -15869,18 +15870,29 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
if (!active && !isVictim && !(procFlag & PROC_FLAG_DONE_PERIODIC) && procSpellInfo && procSpellInfo->SpellFamilyName && (procSpellInfo->HasAura(SPELL_AURA_PERIODIC_DAMAGE) || procSpellInfo->HasAura(SPELL_AURA_PERIODIC_HEAL)))
active = true;
if (!IsTriggeredAtSpellProcEvent(target, triggerData.aura, attType, isVictim, active, triggerData.spellProcEvent, eventInfo))
// AuraScript Hook
if (!triggerData.aura->CallScriptCheckProcHandlers(itr->second, eventInfo))
{
continue;
}
bool isTriggeredAtSpellProcEvent = IsTriggeredAtSpellProcEvent(target, triggerData.aura, attType, isVictim, active, triggerData.spellProcEvent, eventInfo);
// AuraScript Hook
triggerData.aura->CallScriptCheckAfterProcHandlers(itr->second, eventInfo);
if (!isTriggeredAtSpellProcEvent)
{
continue;
}
// do checks using conditions table
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, spellProto->Id);
ConditionSourceInfo condInfo = ConditionSourceInfo(eventInfo.GetActor(), eventInfo.GetActionTarget());
if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions))
{
continue;
// AuraScript Hook
if (!triggerData.aura->CallScriptCheckProcHandlers(itr->second, eventInfo))
continue;
}
// Triggered spells not triggering additional spells
//bool triggered = !spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_FROM_PROCS) ?
@@ -17181,11 +17193,17 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackTyp
}
}
if (eventInfo.GetProcChance())
{
chance = *eventInfo.GetProcChance();
}
// Apply chance modifer aura
if (Player* modOwner = GetSpellModOwner())
{
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance);
}
return roll_chance_f(chance);
}

View File

@@ -25,6 +25,7 @@
#include "HostileRefMgr.h"
#include "MotionMaster.h"
#include "Object.h"
#include "Optional.h"
#include "SpellAuraDefines.h"
#include "SpellDefines.h"
#include "ThreatMgr.h"
@@ -836,6 +837,7 @@ private:
HealInfo* _healInfo;
SpellInfo const* const _triggeredByAuraSpell;
int8 _procAuraEffectIndex;
std::optional<float> _chance;
public:
explicit ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell const* spell, DamageInfo* damageInfo, HealInfo* healInfo, SpellInfo const* triggeredByAuraSpell = nullptr, int8 procAuraEffectIndex = -1);
@@ -855,6 +857,9 @@ public:
[[nodiscard]] int8 GetTriggerAuraEffectIndex() const { return _procAuraEffectIndex; }
[[nodiscard]] uint32 GetProcCooldown() const { return _cooldown; }
void SetProcCooldown(uint32 cooldown) { _cooldown = cooldown; }
[[nodiscard]] std::optional<float> GetProcChance() const { return _chance; }
void SetProcChance(float chance) { _chance = chance; }
void ResetProcChance() { _chance.reset(); }
};
// Struct for use in Unit::CalculateMeleeDamage

View File

@@ -422,6 +422,11 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
std::function<void(PreparedQueryResult)> finalizeCharacterCreation = [this, createInfo](PreparedQueryResult result)
{
if (!sScriptMgr->CanAccountCreateCharacter(createInfo, GetAccountId()))
{
SendCharCreate(CHAR_CREATE_DISABLED);
return;
}
bool haveSameRace = false;
uint32 heroicReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER);
bool hasHeroicReqLevel = (heroicReqLevel == 0);

View File

@@ -153,13 +153,7 @@ void MailDraft::SendReturnToSender(uint32 /*sender_acc*/, ObjectGuid::LowType se
{
Player* receiver = ObjectAccessor::FindPlayerByLowGUID(receiver_guid);
uint32 rc_account = 0;
if (!receiver)
{
rc_account = sCharacterCache->GetCharacterAccountIdByGuid(ObjectGuid(HighGuid::Player, receiver_guid));
}
if (!receiver && !rc_account) // sender not exist
if (!receiver && !sCharacterCache->GetCharacterAccountIdByGuid(ObjectGuid(HighGuid::Player, receiver_guid)))
{
deleteIncludedItems(trans, true);
return;
@@ -200,7 +194,6 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
return;
Player* pReceiver = receiver.GetPlayer(); // can be nullptr
Player* pSender = ObjectAccessor::FindPlayerByLowGUID(sender.GetSenderId());
if (pReceiver)
prepareItems(pReceiver, trans); // generate mail template items
@@ -219,14 +212,14 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
else if (sender.GetMailMessageType() == MAIL_CREATURE && sBattlegroundMgr->GetBattleMasterBG(sender.GetSenderId()) != BATTLEGROUND_TYPE_NONE)
expire_delay = DAY;
// default case: expire time if COD 3 days, if no COD 30 days (or 90 days if sender is a game master)
else if (m_COD)
expire_delay = 3 * DAY;
else if (custom_expiration > 0)
expire_delay = custom_expiration * DAY;
else
{
if (m_COD)
expire_delay = 3 * DAY;
else if (custom_expiration > 0 )
expire_delay = custom_expiration * DAY;
else
expire_delay = pSender && pSender->GetSession()->GetSecurity() ? 90 * DAY : 30 * DAY;
Player* pSender = ObjectAccessor::FindPlayerByLowGUID(sender.GetSenderId());
expire_delay = pSender && pSender->GetSession()->GetSecurity() ? 90 * DAY : 30 * DAY;
}
time_t expire_time = deliver_time + expire_delay;
@@ -235,27 +228,26 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
uint8 index = 0;
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_MAIL);
stmt->SetData( index, mailId);
stmt->SetData (++index, uint8(sender.GetMailMessageType()));
stmt->SetData (++index, int8(sender.GetStationery()));
stmt->SetData(++index, uint8(sender.GetMailMessageType()));
stmt->SetData(++index, int8(sender.GetStationery()));
stmt->SetData(++index, GetMailTemplateId());
stmt->SetData(++index, sender.GetSenderId());
stmt->SetData(++index, receiver.GetPlayerGUIDLow());
stmt->SetData(++index, GetSubject());
stmt->SetData(++index, GetBody());
stmt->SetData (++index, !m_items.empty());
stmt->SetData(++index, !m_items.empty());
stmt->SetData(++index, uint32(expire_time));
stmt->SetData(++index, uint32(deliver_time));
stmt->SetData(++index, m_money);
stmt->SetData(++index, m_COD);
stmt->SetData (++index, uint8(checked));
stmt->SetData(++index, uint8(checked));
trans->Append(stmt);
for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
{
Item* pItem = mailItemIter->second;
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_MAIL_ITEM);
stmt->SetData(0, mailId);
stmt->SetData(1, pItem->GetGUID().GetCounter());
stmt->SetData(1, mailItemIter->second->GetGUID().GetCounter());
stmt->SetData(2, receiver.GetPlayerGUIDLow());
trans->Append(stmt);
}
@@ -302,7 +294,6 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
}
else if (!m_items.empty())
{
CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr);
deleteIncludedItems(temp);
deleteIncludedItems(CharacterDatabaseTransaction(nullptr));
}
}

View File

@@ -81,3 +81,18 @@ void ScriptMgr::OnFailedPasswordChange(uint32 accountId)
script->OnFailedPasswordChange(accountId);
});
}
bool ScriptMgr::CanAccountCreateCharacter(std::shared_ptr<CharacterCreateInfo> createInfo, uint32 accountId)
{
auto ret = IsValidBoolScript<AccountScript>([&](AccountScript* script)
{
return !script->CanAccountCreateCharacter(createInfo, accountId);
});
if (ret && *ret)
{
return false;
}
return true;
}

View File

@@ -936,6 +936,21 @@ void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result,
});
}
bool ScriptMgr::OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll)
{
auto ret = IsValidBoolScript<PlayerScript>([&](PlayerScript* script)
{
return !script->OnUpdateFishingSkill(player, skill, zone_skill, chance, roll);
});
if (ret && *ret)
{
return false;
}
return true;
}
bool ScriptMgr::CanAreaExploreAndOutdoor(Player* player)
{
auto ret = IsValidBoolScript<PlayerScript>([&](PlayerScript* script)

View File

@@ -73,6 +73,7 @@ class Vehicle;
class WorldObject;
class WorldPacket;
class WorldSocket;
class CharacterCreateInfo;
struct AchievementCriteriaData;
struct AuctionEntry;
@@ -1251,6 +1252,8 @@ public:
virtual void OnGetMaxSkillValue(Player* /*player*/, uint32 /*skill*/, int32& /*result*/, bool /*IsPure*/) { }
[[nodiscard]] virtual bool OnUpdateFishingSkill(Player* /*player*/, int32 /*skill*/, int32 /*zone_skill*/, int32 /*chance*/, int32 /*roll*/) { return true; }
[[nodiscard]] virtual bool CanAreaExploreAndOutdoor(Player* /*player*/) { return true; }
virtual void OnVictimRewardBefore(Player* /*player*/, Player* /*victim*/, uint32& /*killer_title*/, uint32& /*victim_title*/) { }
@@ -1458,6 +1461,9 @@ public:
// Called when Password failed to change for Account
virtual void OnFailedPasswordChange(uint32 /*accountId*/) { }
// Called when creating a character on the Account
[[nodiscard]] virtual bool CanAccountCreateCharacter(std::shared_ptr<CharacterCreateInfo> /*createInfo*/, uint32 /*accountId*/) { return true;}
};
class GuildScript : public ScriptObject
@@ -2330,6 +2336,7 @@ public: /* PlayerScript */
void OnDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid);
bool CanRepopAtGraveyard(Player* player);
void OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure);
bool OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll);
bool CanAreaExploreAndOutdoor(Player* player);
void OnVictimRewardBefore(Player* player, Player* victim, uint32& killer_title, uint32& victim_title);
void OnVictimRewardAfter(Player* player, Player* victim, uint32& killer_title, uint32& victim_rank, float& honor_f);
@@ -2394,6 +2401,7 @@ public: /* AccountScript */
void OnFailedEmailChange(uint32 accountId);
void OnPasswordChange(uint32 accountId);
void OnFailedPasswordChange(uint32 accountId);
bool CanAccountCreateCharacter(std::shared_ptr<CharacterCreateInfo> createInfo, uint32 accountId);
public: /* GuildScript */
void OnGuildAddMember(Guild* guild, Player* player, uint8& plRank);

View File

@@ -1450,6 +1450,26 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
else
target->AddAura(74396, target);
}
break;
case 12494: // Frostbite, synchronise with Fingers of Frost
{
// Find Fingers of Frost
if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_MAGE, 2947, EFFECT_0))
{
if (SpellInfo const* triggeringSpellInfo = GetTriggeredByAuraSpellInfo())
{
uint8 fbRank = sSpellMgr->GetSpellRank(triggeringSpellInfo->Id);
uint8 fofRank = sSpellMgr->GetSpellRank(aurEff->GetId());
uint8 chance = uint8(std::ceil(fofRank * fbRank * 16.6f));
if (roll_chance_i(chance))
{
caster->CastSpell(caster, aurEff->GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true);
}
}
}
break;
}
default:
break;
}
@@ -2620,6 +2640,22 @@ bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventI
return result;
}
bool Aura::CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AFTER_PROC, aurApp);
std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckAfterProc.end(), hookItr = (*scritr)->DoCheckAfterProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
result &= hookItr->Call(*scritr, eventInfo);
(*scritr)->_FinishScriptCall();
}
return result;
}
bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool prepare = true;

View File

@@ -226,6 +226,7 @@ public:
// Spell Proc Hooks
bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);

View File

@@ -3278,12 +3278,14 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask)
}
else
{
m_caster->CastCustomSpell(i->triggeredSpell->Id, SPELLVALUE_AURA_DURATION, _duration, unit, true);
AuraEffect const* triggeringAuraEffect = m_caster->GetAuraEffect(i->triggeredByAura->Id, i->triggeredByEffIdx);
m_caster->CastCustomSpell(i->triggeredSpell->Id, SPELLVALUE_AURA_DURATION, _duration, unit, true, nullptr, triggeringAuraEffect);
}
}
else
{
m_caster->CastSpell(unit, i->triggeredSpell, true);
AuraEffect const* triggeringAuraEffect = m_caster->GetAuraEffect(i->triggeredByAura->Id, i->triggeredByEffIdx);
m_caster->CastSpell(unit, i->triggeredSpell, true, nullptr, triggeringAuraEffect);
}
}
}
@@ -8766,6 +8768,7 @@ void Spell::PrepareTriggersExecutedOnHit()
HitTriggerSpell spellTriggerInfo;
spellTriggerInfo.triggeredSpell = spellInfo;
spellTriggerInfo.triggeredByAura = auraSpellInfo;
spellTriggerInfo.triggeredByEffIdx = (*i)->GetEffIndex();
spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount();
m_hitTriggerSpells.push_back(spellTriggerInfo);
}

View File

@@ -741,7 +741,7 @@ public:
{
SpellInfo const* triggeredSpell;
SpellInfo const* triggeredByAura;
// uint8 triggeredByEffIdx This might be needed at a later stage - No need known for now
uint8 triggeredByEffIdx;
int32 chance;
};

View File

@@ -733,6 +733,10 @@ bool AuraScript::_Validate(SpellInfo const* entry)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
for (std::list<CheckProcHandler>::iterator itr = DoCheckAfterProc.begin(); itr != DoCheckAfterProc.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckAfterProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
for (std::list<AuraProcHandler>::iterator itr = DoPrepareProc.begin(); itr != DoPrepareProc.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoPrepareProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
@@ -1163,6 +1167,7 @@ Unit* AuraScript::GetTarget() const
case AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD:
case AURA_SCRIPT_HOOK_EFFECT_SPLIT:
case AURA_SCRIPT_HOOK_CHECK_PROC:
case AURA_SCRIPT_HOOK_CHECK_AFTER_PROC:
case AURA_SCRIPT_HOOK_PREPARE_PROC:
case AURA_SCRIPT_HOOK_PROC:
case AURA_SCRIPT_HOOK_AFTER_PROC:

View File

@@ -499,6 +499,7 @@ enum AuraScriptHookType
AURA_SCRIPT_HOOK_AFTER_DISPEL,
// Spell Proc Hooks
AURA_SCRIPT_HOOK_CHECK_PROC,
AURA_SCRIPT_HOOK_CHECK_AFTER_PROC,
AURA_SCRIPT_HOOK_PREPARE_PROC,
AURA_SCRIPT_HOOK_PROC,
AURA_SCRIPT_HOOK_EFFECT_PROC,
@@ -804,6 +805,10 @@ public:
// example: DoCheckProc += AuraCheckProcFn(class::function);
// where function is: bool function (ProcEventInfo& eventInfo);
HookList<CheckProcHandler> DoCheckProc;
// executed when aura checks if it can proc
// example: DoCheckAfterProc += AuraCheckProcFn(class::function);
// where function is: bool function (ProcEventInfo& eventInfo);
HookList<CheckProcHandler> DoCheckAfterProc;
#define AuraCheckProcFn(F) CheckProcHandlerFunction(&F)
// executed before aura procs (possibility to prevent charge drop/cooldown)