Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-05-24 17:57:30 +08:00
131 changed files with 5656 additions and 2599 deletions
@@ -640,12 +640,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
me->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlags);
LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST: Unit {} casts spell {} on target {} with castflags {}",
me->GetGUID().ToString().c_str(), e.action.cast.spell, target->GetGUID().ToString().c_str(), e.action.cast.castFlags);
me->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
}
else
{
LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target {} already has the aura",
e.action.cast.spell, target->GetGUID().ToString().c_str());
e.action.cast.spell, target->GetGUID().ToString());
}
}
break;
@@ -729,12 +729,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlags);
LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker {} casts spell {} on target {} with castflags {}",
tempLastInvoker->GetGUID().ToString().c_str(), e.action.cast.spell, target->GetGUID().ToString().c_str(), e.action.cast.castFlags);
tempLastInvoker->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
}
else
{
LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target {} already has the aura",
e.action.cast.spell, target->GetGUID().ToString().c_str());
e.action.cast.spell, target->GetGUID().ToString());
}
}
break;
@@ -2797,6 +2797,18 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
break;
}
case SMART_ACTION_DISABLE:
{
for (WorldObject* target : targets)
{
if (IsUnit(target))
{
target->ToUnit()->SetImmuneToAll(!e.action.disable.state);
target->ToUnit()->SetVisible(e.action.disable.state);
}
}
break;
}
default:
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
@@ -762,6 +762,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_LOAD_GRID: return NO_PARAMS;
case SMART_ACTION_MUSIC: return sizeof(SmartAction::music);
case SMART_ACTION_SET_GUID: return sizeof(SmartAction::setGuid);
case SMART_ACTION_DISABLE: return sizeof(SmartAction::disable);
default:
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -1918,6 +1919,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_ATTACK_STOP:
case SMART_ACTION_PLAY_CINEMATIC:
case SMART_ACTION_SET_GUID:
case SMART_ACTION_DISABLE:
break;
default:
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
@@ -693,8 +693,9 @@ enum SMART_ACTION
SMART_ACTION_DO_ACTION = 223, // ActionId
SMART_ACTION_ATTACK_STOP = 224, //
SMART_ACTION_SET_GUID = 225, // Sends the invoker's or the base object's own ObjectGuid to target
SMART_ACTION_DISABLE = 226, // Disable the targeted creatures, setting them Invisible and Immune to All
SMART_ACTION_AC_END = 226, // placeholder
SMART_ACTION_AC_END = 227, // placeholder
};
enum class SmartActionSummonCreatureFlags
@@ -1365,6 +1366,11 @@ struct SmartAction
SAIBool invokerGUID;
uint32 index;
} setGuid;
struct
{
SAIBool state;
} disable;
//! Note for any new future actions
//! All parameters must have type uint32
@@ -2683,7 +2683,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT)
LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has ScriptName set for non-scripted data type (Entry: {}, type {}), useless data.", criteria_id, dataType);
else
scriptId = sObjectMgr->GetScriptId(scriptName.c_str());
scriptId = sObjectMgr->GetScriptId(scriptName);
}
AchievementCriteriaData data(dataType, fields[2].Get<uint32>(), fields[3].Get<uint32>(), scriptId);
+1 -1
View File
@@ -459,7 +459,7 @@ uint32 CalendarMgr::GetPlayerNumPending(ObjectGuid guid)
std::string CalendarEvent::BuildCalendarMailSubject(ObjectGuid remover) const
{
std::ostringstream strm;
strm << remover.ToString().c_str() << ':' << _title;
strm << remover.ToString() << ':' << _title;
return strm.str();
}
+4 -4
View File
@@ -206,7 +206,7 @@ void LoadM2Cameras(std::string const& dataPath)
// Reject if not at least the size of the header
if (static_cast<uint32>(fileSize) < sizeof(M2Header))
{
LOG_ERROR("server.loading", "Camera file {} is damaged. File is smaller than header size", filename.string().c_str());
LOG_ERROR("server.loading", "Camera file {} is damaged. File is smaller than header size", filename.string());
m2file.close();
continue;
}
@@ -220,7 +220,7 @@ void LoadM2Cameras(std::string const& dataPath)
// Check file has correct magic (MD20)
if (strcmp(fileCheck, "MD20"))
{
LOG_ERROR("server.loading", "Camera file {} is damaged. File identifier not found", filename.string().c_str());
LOG_ERROR("server.loading", "Camera file {} is damaged. File identifier not found", filename.string());
m2file.close();
continue;
}
@@ -240,14 +240,14 @@ void LoadM2Cameras(std::string const& dataPath)
if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32>(fileSize))
{
LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string().c_str());
LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string());
continue;
}
// Get camera(s) - Main header, then dump them.
M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras);
if (!readCamera(cam, fileSize, header, dbcentry))
LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string().c_str());
LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string());
}
LOG_INFO("server.loading", ">> Loaded {} Cinematic Waypoint Sets in {} ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime));
+1 -1
View File
@@ -484,7 +484,7 @@ namespace lfg
[[nodiscard]] std::string toString() const // for debugging
{
std::ostringstream o;
o << guids[0].ToString().c_str() << "," << guids[1].ToString().c_str() << "," << guids[2].ToString().c_str() << "," << guids[3].ToString().c_str() << "," << guids[4].ToString().c_str() << ":" << (roles ? 1 : 0);
o << guids[0].ToString() << "," << guids[1].ToString() << "," << guids[2].ToString() << "," << guids[3].ToString() << "," << guids[4].ToString() << ":" << (roles ? 1 : 0);
return o.str();
}
};
+13 -5
View File
@@ -1124,11 +1124,11 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, GetCreateMana());
// xinef: added some multipliers so debuffs can affect pets in any way...
SetCreateStat(STAT_STRENGTH, 22 + 2 * petlevel);
SetCreateStat(STAT_AGILITY, 22 + 1.5f * petlevel);
SetCreateStat(STAT_STAMINA, 25 + 2 * petlevel);
SetCreateStat(STAT_INTELLECT, 28 + 2 * petlevel);
SetCreateStat(STAT_SPIRIT, 27 + 1.5f * petlevel);
SetCreateStat(STAT_STRENGTH, 22);
SetCreateStat(STAT_AGILITY, 22);
SetCreateStat(STAT_STAMINA, 25);
SetCreateStat(STAT_INTELLECT, 28);
SetCreateStat(STAT_SPIRIT, 27);
}
switch (petType)
@@ -1348,6 +1348,14 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
break;
}
case NPC_VENOMOUS_SNAKE:
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 0.7 - 38));
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 0.8 - 40));
break;
case NPC_VIPER:
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(1.3 * petlevel - 64));
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(1.5 * petlevel - 68));
break;
case NPC_GENERIC_IMP:
case NPC_GENERIC_VOIDWALKER:
{
@@ -122,6 +122,10 @@ enum NPCEntries
NPC_ARMY_OF_THE_DEAD = 24207,
NPC_EBON_GARGOYLE = 27829,
// Hunter
NPC_VENOMOUS_SNAKE = 19833,
NPC_VIPER = 19921,
// Generic
NPC_GENERIC_IMP = 12922,
NPC_GENERIC_VOIDWALKER = 8996
@@ -166,6 +166,7 @@ void KillRewarder::_RewardXP(Player* player, float rate)
AddPct(xp, (*i)->GetAmount());
// 4.2.3. Give XP to player.
sScriptMgr->OnGivePlayerXP(player, xp, _victim, PlayerXPSource::XPSOURCE_KILL);
player->GiveXP(xp, _victim, _groupRate);
if (Pet* pet = player->GetPet())
// 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
+9 -5
View File
@@ -2372,8 +2372,6 @@ void Player::GiveXP(uint32 xp, Unit* victim, float group_rate, bool isLFGReward)
uint8 level = GetLevel();
sScriptMgr->OnGivePlayerXP(this, xp, victim);
// Favored experience increase START
uint32 zone = GetZoneId();
float favored_exp_mult = 0;
@@ -5147,7 +5145,7 @@ float Player::OCTRegenHPPerSpirit()
if (baseSpirit > 50)
baseSpirit = 50;
float moreSpirit = spirit - baseSpirit;
float regen = baseSpirit * baseRatio->ratio + moreSpirit * moreRatio->ratio;
float regen = (baseSpirit * baseRatio->ratio + moreSpirit * moreRatio->ratio) * 2;
return regen;
}
@@ -5732,6 +5730,7 @@ void Player::CheckAreaExploreAndOutdoor()
XP = uint32(sObjectMgr->GetBaseXP(areaEntry->area_level) * sWorld->getRate(RATE_XP_EXPLORE));
}
sScriptMgr->OnGivePlayerXP(this, XP, nullptr, PlayerXPSource::XPSOURCE_EXPLORE);
GiveXP(XP, nullptr);
SendExplorationExperience(areaId, XP);
}
@@ -6121,7 +6120,11 @@ bool Player::RewardHonor(Unit* uVictim, uint32 groupsize, int32 honor, bool awar
bg->UpdatePlayerScore(this, SCORE_BONUS_HONOR, honor, false); //false: prevent looping
// Xinef: Only for BG activities
if (!uVictim)
GiveXP(uint32(honor * (3 + GetLevel() * 0.30f)), nullptr);
{
uint32 xp = uint32(honor * (3 + GetLevel() * 0.30f));
sScriptMgr->OnGivePlayerXP(this, xp, nullptr, PlayerXPSource::XPSOURCE_BATTLEGROUND);
GiveXP(xp, nullptr);
}
}
if (sWorld->getBoolConfig(CONFIG_PVP_TOKEN_ENABLE))
@@ -7074,7 +7077,8 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply,
LOG_DEBUG("entities.player", "WORLD: cast {} Equip spellId - {}", (item ? "item" : "itemset"), spellInfo->Id);
CastSpell(this, spellInfo, true, item);
//Ignore spellInfo->DurationEntry, cast with -1 duration
CastCustomSpell(spellInfo->Id, SPELLVALUE_AURA_DURATION, -1, this, true, item);
}
else
{
+10
View File
@@ -995,6 +995,16 @@ enum PlayerCommandStates
CHEAT_WATERWALK = 0x10
};
// Used for OnGiveXP PlayerScript hook
enum PlayerXPSource
{
XPSOURCE_KILL = 0,
XPSOURCE_QUEST = 1,
XPSOURCE_QUEST_DF = 2,
XPSOURCE_EXPLORE = 3,
XPSOURCE_BATTLEGROUND = 4
};
enum InstantFlightGossipAction
{
GOSSIP_ACTION_TOGGLE_INSTANT_FLIGHT = 500
@@ -756,6 +756,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
}
else
{
sScriptMgr->OnGivePlayerXP(this, XP, nullptr, isLFGReward ? PlayerXPSource::XPSOURCE_QUEST_DF : PlayerXPSource::XPSOURCE_QUEST);
GiveXP(XP, nullptr, isLFGReward);
}
@@ -6978,7 +6978,7 @@ bool Player::CheckInstanceLoginValid()
if (GetMap()->IsRaid())
{
// cannot be in raid instance without a group
if (!GetGroup())
if (!GetGroup() && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID))
return false;
}
else
+6 -9
View File
@@ -812,14 +812,8 @@ void Unit::DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb)
}
}
uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss, bool /*allowGM*/, Spell const* damageSpell /*= nullptr*/, bool delayed)
uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss, bool /*allowGM*/, Spell const* damageSpell /*= nullptr*/)
{
if (delayed && attacker->GetTypeId() == TYPEID_PLAYER && attacker->GetGUID() != victim->GetGUID())
{
sWorld->AddDelayedDamage(attacker, victim, damage, cleanDamage, damagetype, damageSchoolMask, spellProto, durabilityLoss);
return 0;
}
// Xinef: initialize damage done for rage calculations
// Xinef: its rare to modify damage in hooks, however training dummy's sets damage to 0
uint32 rage_damage = damage + ((cleanDamage != nullptr) ? cleanDamage->absorbed_damage : 0);
@@ -1460,7 +1454,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss,
// Call default DealDamage
CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss, false, spell, true);
Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss, false, spell);
}
// @todo for melee need create structure as in
@@ -10392,7 +10386,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
creature->SendAIReaction(AI_REACTION_HOSTILE);
/// @todo: Implement aggro range, detection range and assistance range templates
if (!(creature->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE))
if (!(creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE))
{
creature->CallAssistance();
}
@@ -20081,6 +20075,9 @@ void Unit::_ExitVehicle(Position const* exitPosition)
Unit* vehicleBase = m_vehicle->GetBase();
m_vehicle = nullptr;
if (!vehicleBase)
return;
SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
Position pos;
+1 -13
View File
@@ -757,18 +757,6 @@ struct CleanDamage
struct CalcDamageInfo;
struct SpellNonMeleeDamage;
struct DelayedDamage
{
Unit* attacker;
Unit* victim;
uint32 damage;
CleanDamage const* cleanDamage;
DamageEffectType damagetype;
SpellSchoolMask damageSchoolMask;
SpellInfo const* spellProto;
bool durabilityLoss;
};
class DamageInfo
{
private:
@@ -1571,7 +1559,7 @@ public:
uint16 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : GetLevel()) * 5; }
static void DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb);
static uint32 DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true, bool allowGM = false, Spell const* spell = nullptr, bool delayed = false);
static uint32 DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true, bool allowGM = false, Spell const* spell = nullptr);
static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr);
void KillSelf(bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr) { Kill(this, this, durabilityLoss, attackType, spellProto, spell); };
static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth);
+2 -2
View File
@@ -2885,7 +2885,7 @@ void ObjectMgr::LoadItemTemplates()
}
if (itemTemplate.Material != dbcitem->Material)
{
LOG_ERROR("sql.sql", "Item (Entry: {%u}}) does not have a correct material ({}), must be {}.", entry, itemTemplate.Material, dbcitem->Material);
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct material ({}), must be {}.", entry, itemTemplate.Material, dbcitem->Material);
if (enforceDBCAttributes)
itemTemplate.Material = dbcitem->Material;
}
@@ -2897,7 +2897,7 @@ void ObjectMgr::LoadItemTemplates()
}
if (itemTemplate.DisplayInfoID != dbcitem->DisplayInfoID)
{
LOG_ERROR("sql.sql", "Item (Entry: {%u}}) does not have a correct display id ({}), must be {}.", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayInfoID);
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct display id ({}), must be {}.", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayInfoID);
if (enforceDBCAttributes)
itemTemplate.DisplayInfoID = dbcitem->DisplayInfoID;
}
+1 -1
View File
@@ -55,7 +55,7 @@ void WorldSession::HandleLfgJoinOpcode(WorldPackets::LFG::LFGJoin& packet)
if (packet.Slots.empty())
{
LOG_DEBUG("lfg", "CMSG_LFG_JOIN {} no dungeons selected", GetPlayerInfo().c_str());
LOG_DEBUG("lfg", "CMSG_LFG_JOIN {} no dungeons selected", GetPlayerInfo());
return;
}
+3 -3
View File
@@ -953,21 +953,21 @@ void WorldSession::HandlePetSpellAutocastOpcode(WorldPackets::Pet::PetSpellAutoc
Creature* checkPet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, packet.PetGUID);
if (!checkPet)
{
LOG_ERROR("entities.pet", "WorldSession::HandlePetSpellAutocastOpcode: Pet {} not found.", packet.PetGUID.ToString().c_str());
LOG_ERROR("entities.pet", "WorldSession::HandlePetSpellAutocastOpcode: Pet {} not found.", packet.PetGUID.ToString());
return;
}
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.SpellID);
if (!spellInfo)
{
LOG_ERROR("spells.pet", "WorldSession::HandlePetSpellAutocastOpcode: Unknown spell id {} used by {}.", packet.SpellID, packet.PetGUID.ToString().c_str());
LOG_ERROR("spells.pet", "WorldSession::HandlePetSpellAutocastOpcode: Unknown spell id {} used by {}.", packet.SpellID, packet.PetGUID.ToString());
return;
}
if (checkPet != _player->GetGuardianPet() && checkPet != _player->GetCharm())
{
LOG_ERROR("entities.pet", "WorldSession::HandlePetSpellAutocastOpcode: {} isn't pet of player {} ({}).",
packet.PetGUID.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str());
packet.PetGUID.ToString(), GetPlayer()->GetName(), GetPlayer()->GetGUID().ToString());
return;
}
+38 -9
View File
@@ -100,7 +100,7 @@ public:
bool HasQuestDrop(LootTemplateMap const& store) const; // True if group includes at least 1 quest drop entry
bool HasQuestDropForPlayer(Player const* player, LootTemplateMap const& store) const;
// The same for active quests of the player
void Process(Loot& loot, Player const* player, LootStore const& lootstore, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
void Process(Loot& loot, Player const* player, LootStore const& lootstore, uint16 lootMode, uint16 nonRefIterationsLeft) const; // Rolls an item from the group (if any) and adds the item to the loot
float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
float TotalChance() const; // Overall chance for the group
@@ -570,7 +570,8 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
items.reserve(MAX_NR_LOOT_ITEMS);
quest_items.reserve(MAX_NR_QUEST_ITEMS);
tab->Process(*this, store, lootMode, lootOwner); // Processing is done there, callback via Loot::AddItem()
// Initial group is 0, top level set to True
tab->Process(*this, store, lootMode, lootOwner, 0, true); // Processing is done there, callback via Loot::AddItem()
sScriptMgr->OnAfterLootTemplateProcess(this, tab, store, lootOwner, personal, noEmptyError, lootMode);
@@ -1413,7 +1414,7 @@ void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/)
}
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStore const& store, uint16 lootMode) const
void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStore const& store, uint16 lootMode, uint16 nonRefIterationsLeft) const
{
if (LootStoreItem const* item = Roll(loot, player, store, lootMode))
{
@@ -1426,7 +1427,9 @@ void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStor
uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
sScriptMgr->OnAfterRefCount(player, loot, rate, lootMode, const_cast<LootStoreItem*>(item), maxcount, store);
for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
Referenced->Process(loot, store, lootMode, player, item->groupid);
// This reference needs to be processed further, but it is marked isTopLevel=false so that any groups inside
// the reference are not multiplied by Rate.Drop.Item.GroupAmount
Referenced->Process(loot, store, lootMode, player, item->groupid, false);
}
}
else
@@ -1434,6 +1437,14 @@ void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStor
// Plain entries (not a reference, not grouped)
sScriptMgr->OnBeforeDropAddItem(player, loot, rate, lootMode, const_cast<LootStoreItem*>(item), store);
loot.AddItem(*item); // Chance is already checked, just add
// If we still have non-ref runs to do for this group AND this item wasn't a reference,
// recursively call this function to produce more items for this group.
// However, if this is a quest item we shouldn't multiply this group.
if (nonRefIterationsLeft > 1 && !item->needs_quest)
{
this->Process(loot, player, store, lootMode, nonRefIterationsLeft-1);
}
}
}
}
@@ -1665,7 +1676,7 @@ bool LootTemplate::CopyConditions(LootItem* li, uint32 conditionLootId) const
}
// Rolls for every item in the template and adds the rolled items the the loot
void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId) const
void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId, bool isTopLevel) const
{
bool rate = store.IsRatesAllowed();
@@ -1677,7 +1688,15 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode,
if (!Groups[groupId - 1])
return;
Groups[groupId - 1]->Process(loot, player, store, lootMode);
// Rate.Drop.Item.GroupAmount is only in effect for the top loot template level
if (isTopLevel)
{
Groups[groupId - 1]->Process(loot, player, store, lootMode, sWorld->getRate(RATE_DROP_ITEM_GROUP_AMOUNT));
}
else
{
Groups[groupId - 1]->Process(loot, player, store, lootMode, 0);
}
return;
}
@@ -1687,7 +1706,6 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode,
LootStoreItem* item = *i;
if (!(item->lootmode & lootMode)) // Do not add if mode mismatch
continue;
if (!item->Roll(rate, player, loot, store))
continue; // Bad luck for the entry
@@ -1700,7 +1718,8 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode,
uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
sScriptMgr->OnAfterRefCount(player, loot, rate, lootMode, item, maxcount, store);
for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
Referenced->Process(loot, store, lootMode, player, item->groupid);
// we're no longer in the top level, so isTopLevel is false
Referenced->Process(loot, store, lootMode, player, item->groupid, false);
}
else
{
@@ -1713,7 +1732,17 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode,
// Now processing groups
for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
if (LootGroup* group = *i)
group->Process(loot, player, store, lootMode);
{
// Rate.Drop.Item.GroupAmount is only in effect for the top loot template level
if (isTopLevel)
{
group->Process(loot, player, store, lootMode, sWorld->getRate(RATE_DROP_ITEM_GROUP_AMOUNT));
}
else
{
group->Process(loot, player, store, lootMode, 0);
}
}
}
// True if template includes at least 1 quest drop entry
+1 -1
View File
@@ -253,7 +253,7 @@ public:
// Adds an entry to the group (at loading stage)
void AddEntry(LootStoreItem* item);
// Rolls for every item in the template and adds the rolled items the the loot
void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0) const;
void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0, bool isTopLevel = true) const;
void CopyConditions(ConditionList conditions);
bool CopyConditions(LootItem* li, uint32 conditionLootId = 0) const;
+1 -1
View File
@@ -30,7 +30,7 @@ class Item;
class Object;
class Player;
#define MAIL_BODY_ITEM_TEMPLATE 8383 // - plain letter, A Dusty Unsent Letter: 889
#define MAIL_BODY_ITEM_TEMPLATE 9311 // - plain letter, A Dusty Unsent Letter: 889
#define MAX_MAIL_ITEMS 12
enum MailMessageType
@@ -375,7 +375,7 @@ void FlightPathMovementGenerator::DoReset(Player* player)
if (currentNodeId == end)
{
LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::DoReset: trying to start a flypath from the end point. {}", player->GetGUID().ToString().c_str());
LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::DoReset: trying to start a flypath from the end point. {}", player->GetGUID().ToString());
return;
}
@@ -406,7 +406,7 @@ bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
bool departureEvent = true;
do
{
ASSERT(i_currentNode < i_path.size(), "Point Id: {}\n{}", pointId, player->GetGUID().ToString().c_str());
ASSERT(i_currentNode < i_path.size(), "Point Id: {}\n{}", pointId, player->GetGUID().ToString());
DoEventIfAny(player, i_path[i_currentNode], departureEvent);
while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front().PathIndex <= i_currentNode)
@@ -460,7 +460,7 @@ void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry
{
if (uint32 eventid = departure ? node->departureEventID : node->arrivalEventID)
{
LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName().c_str());
LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName());
player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
}
}
+7 -7
View File
@@ -113,9 +113,9 @@ inline Player* Map::_GetScriptPlayerSourceOrTarget(Object* source, Object* targe
if (!player)
LOG_ERROR("maps.script", "{} neither source nor target object is player (source: TypeId: {}, Entry: {}, GUID: {}; target: TypeId: {}, Entry: {}, GUID: {}), skipping.",
scriptInfo->GetDebugInfo().c_str(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUID().ToString().c_str() : "",
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUID().ToString().c_str() : "");
scriptInfo->GetDebugInfo(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUID().ToString() : "",
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUID().ToString() : "");
}
return player;
}
@@ -146,9 +146,9 @@ inline Creature* Map::_GetScriptCreatureSourceOrTarget(Object* source, Object* t
if (!creature)
LOG_ERROR("maps.script", "{} neither source nor target are creatures (source: TypeId: {}, Entry: {}, GUID: {}; target: TypeId: {}, Entry: {}, GUID: {}), skipping.",
scriptInfo->GetDebugInfo().c_str(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUID().ToString().c_str() : "",
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUID().ToString().c_str() : "");
scriptInfo->GetDebugInfo(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUID().ToString() : "",
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUID().ToString() : "");
}
return creature;
}
@@ -533,7 +533,7 @@ void Map::ScriptsProcess()
else
{
LOG_ERROR("maps.script", "{} neither source nor target is player (source: {}; target: {}), skipping.",
step.script->GetDebugInfo().c_str(), source->GetGUID().ToString().c_str(), target->GetGUID().ToString().c_str());
step.script->GetDebugInfo(), source->GetGUID().ToString(), target->GetGUID().ToString());
break;
}
}
@@ -154,11 +154,11 @@ void ScriptMgr::OnBeforeLootMoney(Player* player, Loot* loot)
});
}
void ScriptMgr::OnGivePlayerXP(Player* player, uint32& amount, Unit* victim)
void ScriptMgr::OnGivePlayerXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource)
{
ExecuteScript<PlayerScript>([&](PlayerScript* script)
{
script->OnGiveXP(player, amount, victim);
script->OnGiveXP(player, amount, victim, xpSource);
});
}
+1 -1
View File
@@ -161,7 +161,7 @@ void ScriptMgr::CheckIfScriptsInDatabaseExist()
{
for (auto const& scriptName : sObjectMgr->GetScriptNames())
{
if (uint32 sid = sObjectMgr->GetScriptId(scriptName.c_str()))
if (uint32 sid = sObjectMgr->GetScriptId(scriptName))
{
if (!ScriptRegistry<SpellScriptLoader>::GetScriptById(sid) &&
!ScriptRegistry<ServerScript>::GetScriptById(sid) &&
+2 -2
View File
@@ -1037,7 +1037,7 @@ public:
virtual void OnBeforeLootMoney(Player* /*player*/, Loot* /*loot*/) {}
// Called when a player gains XP (before anything is given)
virtual void OnGiveXP(Player* /*player*/, uint32& /*amount*/, Unit* /*victim*/) { }
virtual void OnGiveXP(Player* /*player*/, uint32& /*amount*/, Unit* /*victim*/, uint8 /*xpSource*/) { }
// Called when a player's reputation changes (before it is actually changed)
virtual bool OnReputationChange(Player* /*player*/, uint32 /*factionID*/, int32& /*standing*/, bool /*incremental*/) { return true; }
@@ -2281,7 +2281,7 @@ public: /* PlayerScript */
void OnPlayerTalentsReset(Player* player, bool noCost);
void OnPlayerMoneyChanged(Player* player, int32& amount);
void OnBeforeLootMoney(Player* player, Loot* loot);
void OnGivePlayerXP(Player* player, uint32& amount, Unit* victim);
void OnGivePlayerXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource);
bool OnPlayerReputationChange(Player* player, uint32 factionID, int32& standing, bool incremental);
void OnPlayerReputationRankChange(Player* player, uint32 factionID, ReputationRank newRank, ReputationRank oldRank, bool increased);
void OnPlayerLearnSpell(Player* player, uint32 spellID);
@@ -6387,7 +6387,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true, false);
Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
}
+5 -11
View File
@@ -3430,19 +3430,13 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
}
case SPELLFAMILY_PALADIN:
{
// Seal of Command Unleashed
if (m_spellInfo->Id == 20467)
{
spell_bonus += int32(0.08f * m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
spell_bonus += int32(0.13f * m_caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()));
}
switch (m_spellInfo->Id)
{
case 20424: // Seal of Command
case 42463: // Seal of Vengeance
case 53739: // Seal of Corruption
case 53385: // Divine Storm
case 20467: // Seal of Command Unleashed
spell_bonus += int32(0.08f * m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
spell_bonus += int32(0.13f * m_caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()));
break;
case 53385: // Divine Storm deals normalized damage
normalized = true;
break;
default:
+1
View File
@@ -2104,6 +2104,7 @@ AuraStateType SpellInfo::LoadAuraState() const
case 35331: // Black Blood
case 9806: // Phantom Strike
case 35325: // Glowing Blood
case 35328: // Lambent Blood
case 16498: // Faerie Fire
case 6950:
case 20656:
@@ -213,6 +213,15 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->MaxAffectedTargets = 4;
});
ApplySpellFix({
20424, // Seal of Command
42463, // Seal of Vengeance
53739 // Seal of Corruption
}, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_CASTER_MODIFIERS;
});
// Spitfire Totem
ApplySpellFix({ 38296 }, [](SpellInfo* spellInfo)
{
@@ -4500,6 +4509,31 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE;
});
// Absorb Life
ApplySpellFix({ 34239 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].ValueMultiplier = 1;
});
// Summon a Warp Rift in Void Ridge
ApplySpellFix({ 35036 }, [](SpellInfo* spellInfo)
{
spellInfo->CastTimeEntry = sSpellCastTimesStore.LookupEntry(1); // 0s
});
// Hit Rating (Dungeon T3 - 2P Bonus - Wastewalker, Doomplate)
ApplySpellFix({ 37608, 37610 }, [](SpellInfo* spellInfo)
{
spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(0);
spellInfo->Effects[EFFECT_0].MiscValue = 224;
});
// Target Fissures
ApplySpellFix({ 30745 }, [](SpellInfo* spellInfo)
{
spellInfo->MaxAffectedTargets = 1;
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];
-35
View File
@@ -1,35 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "IWorld.h"
class Unit;
class IWorld;
void IWorld::AddDelayedDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
{
DelayedDamage delayedDamage;
delayedDamage.attacker = attacker;
delayedDamage.victim = victim;
delayedDamage.damage = damage;
delayedDamage.cleanDamage = cleanDamage;
delayedDamage.damagetype = damagetype;
delayedDamage.damageSchoolMask = damageSchoolMask;
delayedDamage.spellProto = spellProto;
delayedDamage.durabilityLoss = durabilityLoss;
_delayedDamages.push_back(delayedDamage);
}
+2 -7
View File
@@ -24,17 +24,15 @@
#include "ObjectGuid.h"
#include "QueryResult.h"
#include "SharedDefines.h"
#include "Unit.h"
#include <atomic>
#include <list>
#include <map>
#include <set>
#include <unordered_map>
class IWorld;
class Player;
class WorldPacket;
class WorldSession;
class Player;
/// Storage class for commands issued for delayed execution
struct AC_GAME_API CliCommandHolder
@@ -438,8 +436,8 @@ enum Rates
RATE_DROP_ITEM_LEGENDARY,
RATE_DROP_ITEM_ARTIFACT,
RATE_DROP_ITEM_REFERENCED,
RATE_DROP_ITEM_REFERENCED_AMOUNT,
RATE_DROP_ITEM_GROUP_AMOUNT,
RATE_SELLVALUE_ITEM_POOR,
RATE_SELLVALUE_ITEM_NORMAL,
RATE_SELLVALUE_ITEM_UNCOMMON,
@@ -518,13 +516,10 @@ enum Rates
class IWorld
{
public:
std::list<DelayedDamage> _delayedDamages;
virtual ~IWorld() = default;
[[nodiscard]] virtual WorldSession* FindSession(uint32 id) const = 0;
[[nodiscard]] virtual WorldSession* FindOfflineSession(uint32 id) const = 0;
[[nodiscard]] virtual WorldSession* FindOfflineSessionForCharacterGUID(ObjectGuid::LowType guidLow) const = 0;
virtual void AddDelayedDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss);
virtual void AddSession(WorldSession* s) = 0;
virtual bool KickSession(uint32 id) = 0;
virtual void UpdateMaxSessionCounters() = 0;
+2 -29
View File
@@ -493,7 +493,9 @@ void World::LoadConfigSettings(bool reload)
_rate_values[RATE_DROP_ITEM_ARTIFACT] = sConfigMgr->GetOption<float>("Rate.Drop.Item.Artifact", 1.0f);
_rate_values[RATE_DROP_ITEM_REFERENCED] = sConfigMgr->GetOption<float>("Rate.Drop.Item.Referenced", 1.0f);
_rate_values[RATE_DROP_ITEM_REFERENCED_AMOUNT] = sConfigMgr->GetOption<float>("Rate.Drop.Item.ReferencedAmount", 1.0f);
_rate_values[RATE_DROP_ITEM_GROUP_AMOUNT] = sConfigMgr->GetOption<float>("Rate.Drop.Item.GroupAmount", 1.0f);
_rate_values[RATE_DROP_MONEY] = sConfigMgr->GetOption<float>("Rate.Drop.Money", 1.0f);
_rate_values[RATE_REWARD_BONUS_MONEY] = sConfigMgr->GetOption<float>("Rate.RewardBonusMoney", 1.0f);
_rate_values[RATE_XP_KILL] = sConfigMgr->GetOption<float>("Rate.XP.Kill", 1.0f);
_rate_values[RATE_XP_BG_KILL_AV] = sConfigMgr->GetOption<float>("Rate.XP.BattlegroundKillAV", 1.0f);
@@ -2065,8 +2067,6 @@ void World::SetInitialWorldSettings()
_mail_expire_check_timer = GameTime::GetGameTime() + 6h;
_timers[WUPDATE_DELAYED_DAMAGES].SetInterval(400);
///- Initialize MapMgr
LOG_INFO("server.loading", "Starting Map System");
LOG_INFO("server.loading", " ");
@@ -2313,12 +2313,6 @@ void World::Update(uint32 diff)
{
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Check quest reset times"));
if (_timers[WUPDATE_DELAYED_DAMAGES].Passed())
{
_timers[WUPDATE_DELAYED_DAMAGES].Reset();
ProcessDelayedDamages();
}
/// Handle daily quests reset time
if (currentGameTime > _nextDailyQuestReset)
{
@@ -3351,24 +3345,3 @@ CliCommandHolder::~CliCommandHolder()
{
free(m_command);
}
void World::AddDelayedDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
{
DelayedDamage delayedDamage;
delayedDamage.attacker = attacker;
delayedDamage.victim = victim;
delayedDamage.damage = damage;
delayedDamage.cleanDamage = cleanDamage;
delayedDamage.damagetype = damagetype;
delayedDamage.damageSchoolMask = damageSchoolMask;
delayedDamage.spellProto = spellProto;
delayedDamage.durabilityLoss = durabilityLoss;
_delayedDamages.push_back(delayedDamage);
}
void World::ProcessDelayedDamages()
{
for (auto& damage : _delayedDamages)
Unit::DealDamage(damage.attacker, damage.victim, damage.damage, damage.cleanDamage, damage.damagetype, damage.damageSchoolMask, damage.spellProto, damage.durabilityLoss);
_delayedDamages.clear();
}
-8
View File
@@ -28,7 +28,6 @@
#include "QueryResult.h"
#include "SharedDefines.h"
#include "Timer.h"
#include "Unit.h"
#include <atomic>
#include <list>
#include <map>
@@ -71,7 +70,6 @@ enum WorldTimers
WUPDATE_PINGDB,
WUPDATE_5_SECS,
WUPDATE_WHO_LIST,
WUPDATE_DELAYED_DAMAGES,
WUPDATE_COUNT
};
@@ -155,8 +153,6 @@ public:
World();
~World() override;
std::list<DelayedDamage> _delayedDamages;
static World* instance();
static uint32 m_worldLoopCounter;
@@ -357,10 +353,6 @@ public:
void RemoveOldCorpses() override;
void AddDelayedDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss) override;
void ProcessDelayedDamages();
protected:
void _UpdateGameTime();
// callback for UpdateRealmCharacters