Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2023-05-01 10:31:02 -06:00
committed by GitHub
39 changed files with 612 additions and 88 deletions
@@ -1309,6 +1309,14 @@ DeletedCharacterTicketTrace = 0
DungeonFinder.OptionsMask = 5
#
# DBC.EnforceItemAttributes
# Disallow overriding item attributes stored in DBC files with values from the database
# Default: 0 - Off, Use DB values
# 1 - On, Enforce DBC Values (default)
DBC.EnforceItemAttributes = 1
#
# AccountInstancesPerHour
# Description: Controls the max amount of different instances player can enter within hour
@@ -2007,7 +2007,7 @@ private:
bool IsItemValid(SmartScriptHolder const& e, uint32 entry)
{
if (!sObjectMgr->GetItemTemplate(entry))
if (!sItemStore.LookupEntry(entry))
{
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Item entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
return false;
+13 -4
View File
@@ -108,6 +108,7 @@ DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptf
DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
DBCStorage <ItemEntry> sItemStore(Itemfmt);
DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt);
//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt);
@@ -329,6 +330,7 @@ void LoadDBCStores(const std::string& dataPath)
LOAD_DBC(sGtRegenHPPerSptStore, "gtRegenHPPerSpt.dbc", "gtregenhpperspt_dbc");
LOAD_DBC(sGtRegenMPPerSptStore, "gtRegenMPPerSpt.dbc", "gtregenmpperspt_dbc");
LOAD_DBC(sHolidaysStore, "Holidays.dbc", "holidays_dbc");
LOAD_DBC(sItemStore, "Item.dbc", "item_dbc");
LOAD_DBC(sItemBagFamilyStore, "ItemBagFamily.dbc", "itembagfamily_dbc");
LOAD_DBC(sItemDisplayInfoStore, "ItemDisplayInfo.dbc", "itemdisplayinfo_dbc");
//LOAD_DBC(sItemCondExtCostsStore, "ItemCondExtCosts.dbc", "itemcondextcosts_dbc");
@@ -650,9 +652,10 @@ void LoadDBCStores(const std::string& dataPath)
}
// Check loaded DBC files proper version
if (!sAreaTableStore.LookupEntry(4987) || // last area added in 3.3.5a
if (!sAreaTableStore.LookupEntry(4987) || // last area added in 3.3.5a
!sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a
!sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a
!sItemStore.LookupEntry(56806) || // last client known item added in 3.3.5a
!sItemExtendedCostStore.LookupEntry(2997) || // last item extended cost added in 3.3.5a
!sMapStore.LookupEntry(724) || // last map added in 3.3.5a
!sSpellStore.LookupEntry(80864) ) // last client known item added in 3.3.5a
@@ -875,9 +878,15 @@ CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType
/// Returns LFGDungeonEntry for a specific map and difficulty. Will return first found entry if multiple dungeons use the same map (such as Scarlet Monastery)
LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty)
{
for (LFGDungeonEntry const* dungeon : sLFGDungeonStore)
if (dungeon->map == int32(mapId) && Difficulty(dungeon->difficulty) == difficulty)
for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i)
{
LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i);
if (!dungeon)
continue;
if (dungeon->MapID == uint32(mapId) && Difficulty(dungeon->Difficulty) == difficulty)
return dungeon;
}
return nullptr;
}
@@ -886,7 +895,7 @@ LFGDungeonEntry const* GetZoneLFGDungeonEntry(std::string const& zoneName, Local
{
for (LFGDungeonEntry const* dungeon : sLFGDungeonStore)
{
if (dungeon->type == lfg::LFG_TYPE_ZONE && zoneName.find(dungeon->name[locale]) != std::string::npos)
if (dungeon->TypeID == lfg::LFG_TYPE_ZONE && zoneName.find(dungeon->Name[locale]) != std::string::npos)
{
return dungeon;
}
+1
View File
@@ -130,6 +130,7 @@ extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
extern DBCStorage <HolidaysEntry> sHolidaysStore;
extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore;
extern DBCStorage <ItemEntry> sItemStore;
extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore;
extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore;
+1 -1
View File
@@ -189,7 +189,7 @@ namespace lfg
if (!dungeon)
continue;
switch (dungeon->type)
switch (dungeon->TypeID)
{
case LFG_TYPE_DUNGEON:
case LFG_TYPE_HEROIC:
+4 -4
View File
@@ -394,10 +394,10 @@ namespace lfg
{
LFGDungeonData(): name("")
{ }
LFGDungeonData(LFGDungeonEntry const* dbc): id(dbc->ID), name(dbc->name[0]), map(dbc->map),
type(dbc->type), expansion(dbc->expansion), group(dbc->grouptype),
minlevel(dbc->minlevel), maxlevel(dbc->maxlevel), difficulty(Difficulty(dbc->difficulty)),
seasonal(dbc->flags & LFG_FLAG_SEASONAL), x(0.0f), y(0.0f), z(0.0f), o(0.0f)
LFGDungeonData(LFGDungeonEntry const* dbc) : id(dbc->ID), name(dbc->Name[0]), map(dbc->MapID),
type(dbc->TypeID), expansion(uint8(dbc->ExpansionLevel)), group(uint8(dbc->GroupID)),
minlevel(uint8(dbc->MinLevel)), maxlevel(uint8(dbc->MaxLevel)), difficulty(Difficulty(dbc->Difficulty)),
seasonal((dbc->Flags & LFG_FLAG_SEASONAL) != 0), x(0.0f), y(0.0f), z(0.0f), o(0.0f)
{ }
uint32 id{0};
+1 -1
View File
@@ -451,7 +451,7 @@ namespace lfg
{
if (Player* player = ObjectAccessor::FindConnectedPlayer(itRoles->first))
{
if (player->GetMapId() == static_cast<uint32>(dungeon->map))
if (player->GetMapId() == static_cast<uint32>(dungeon->MapID))
{
if (InstanceScript* instance = player->GetInstanceScript())
{
+1 -1
View File
@@ -5879,7 +5879,7 @@ void Player::RewardReputation(Unit* victim, float rate)
Map const* map = GetMap();
if (map->IsNonRaidDungeon())
if (LFGDungeonEntry const* dungeon = GetLFGDungeon(map->GetId(), map->GetDifficulty()))
if (dungeon->reclevel == 80)
if (dungeon->TargetLevel == 80)
ChampioningFaction = GetChampioningFaction();
}
+11 -2
View File
@@ -812,8 +812,14 @@ 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*/)
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)
{
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);
@@ -1454,7 +1460,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);
Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss, false, spell, true);
}
// @todo for melee need create structure as in
@@ -20189,7 +20195,10 @@ void Unit::_ExitVehicle(Position const* exitPosition)
}
if (player)
{
player->ResummonPetTemporaryUnSummonedIfAny();
player->SetCanTeleport(true);
}
}
void Unit::BuildMovementPacket(ByteBuffer* data) const
+13 -1
View File
@@ -757,6 +757,18 @@ 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:
@@ -1559,7 +1571,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);
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 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);
+94 -36
View File
@@ -1595,9 +1595,9 @@ void ObjectMgr::LoadEquipmentTemplates()
if (!equipmentInfo.ItemEntry[i])
continue;
ItemTemplate const* item = GetItemTemplate(equipmentInfo.ItemEntry[i]);
ItemEntry const* dbcItem = sItemStore.LookupEntry(equipmentInfo.ItemEntry[i]);
if (!item)
if (!dbcItem)
{
LOG_ERROR("sql.sql", "Unknown item (ID={}) in creature_equip_template.ItemID{} for CreatureID = {} and ID = {}, forced to 0.",
equipmentInfo.ItemEntry[i], i + 1, entry, id);
@@ -1605,15 +1605,15 @@ void ObjectMgr::LoadEquipmentTemplates()
continue;
}
if (item->InventoryType != INVTYPE_WEAPON &&
item->InventoryType != INVTYPE_SHIELD &&
item->InventoryType != INVTYPE_RANGED &&
item->InventoryType != INVTYPE_2HWEAPON &&
item->InventoryType != INVTYPE_WEAPONMAINHAND &&
item->InventoryType != INVTYPE_WEAPONOFFHAND &&
item->InventoryType != INVTYPE_HOLDABLE &&
item->InventoryType != INVTYPE_THROWN &&
item->InventoryType != INVTYPE_RANGEDRIGHT)
if (dbcItem->InventoryType != INVTYPE_WEAPON &&
dbcItem->InventoryType != INVTYPE_SHIELD &&
dbcItem->InventoryType != INVTYPE_RANGED &&
dbcItem->InventoryType != INVTYPE_2HWEAPON &&
dbcItem->InventoryType != INVTYPE_WEAPONMAINHAND &&
dbcItem->InventoryType != INVTYPE_WEAPONOFFHAND &&
dbcItem->InventoryType != INVTYPE_HOLDABLE &&
dbcItem->InventoryType != INVTYPE_THROWN &&
dbcItem->InventoryType != INVTYPE_RANGEDRIGHT)
{
LOG_ERROR("sql.sql", "Item (ID={}) in creature_equip_template.ItemID{} for CreatureID = {} and ID = {} is not equipable in a hand, forced to 0.",
equipmentInfo.ItemEntry[i], i + 1, entry, id);
@@ -2741,8 +2741,10 @@ void ObjectMgr::LoadItemTemplates()
return;
}
_itemTemplateStore.rehash(result->GetRowCount());
_itemTemplateStore.reserve(result->GetRowCount());
uint32 count = 0;
// original inspiration https://github.com/TrinityCore/TrinityCore/commit/0c44bd33ee7b42c924859139a9f4b04cf2b91261
bool enforceDBCAttributes = sWorld->getBoolConfig(CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES);
do
{
@@ -2859,17 +2861,55 @@ void ObjectMgr::LoadItemTemplates()
itemTemplate.FlagsCu = fields[137].Get<uint32>();
// Checks
if (itemTemplate.Class >= MAX_ITEM_CLASS)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Class value ({})", entry, itemTemplate.Class);
itemTemplate.Class = ITEM_CLASS_MISC;
}
ItemEntry const* dbcitem = sItemStore.LookupEntry(entry);
if (itemTemplate.SubClass >= MaxItemSubclassValues[itemTemplate.Class])
if (dbcitem)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Subclass value ({}) for class {}", entry, itemTemplate.SubClass, itemTemplate.Class);
itemTemplate.SubClass = 0;// exist for all item classes
if (itemTemplate.Class != dbcitem->ClassID)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Class value ({}), must be ({}).", entry, itemTemplate.Class, dbcitem->ClassID);
if (enforceDBCAttributes)
itemTemplate.Class = dbcitem->ClassID;
}
if (itemTemplate.SubClass != dbcitem->SubclassID)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Subclass value ({}) for class {}, must be ({}).", entry, itemTemplate.SubClass, itemTemplate.Class, dbcitem->SubclassID);
if (enforceDBCAttributes)
itemTemplate.SubClass = dbcitem->SubclassID;
}
if (itemTemplate.SoundOverrideSubclass != dbcitem->SoundOverrideSubclassID)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct SoundOverrideSubclass ({}), must be {}.", entry, itemTemplate.SoundOverrideSubclass);
if (enforceDBCAttributes)
itemTemplate.SoundOverrideSubclass = dbcitem->SoundOverrideSubclassID;
}
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);
if (enforceDBCAttributes)
itemTemplate.Material = dbcitem->Material;
}
if (itemTemplate.InventoryType != dbcitem->InventoryType)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong InventoryType value ({}), must be {}.", entry, itemTemplate.InventoryType, dbcitem->InventoryType);
if (enforceDBCAttributes)
itemTemplate.InventoryType = dbcitem->InventoryType;
}
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);
if (enforceDBCAttributes)
itemTemplate.DisplayInfoID = dbcitem->DisplayInfoID;
}
if (itemTemplate.Sheath != dbcitem->SheatheType)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Sheath ({}), must be {}.", entry, itemTemplate.Sheath, dbcitem->SheatheType);
if (enforceDBCAttributes)
itemTemplate.Sheath = dbcitem->SheatheType;
}
}
else
LOG_ERROR("sql.sql", "Item (Entry: {}) does not exist in item.dbc! (not correct id?).", entry);
if (itemTemplate.Quality >= MAX_ITEM_QUALITY)
{
@@ -2902,12 +2942,6 @@ void ObjectMgr::LoadItemTemplates()
itemTemplate.BuyCount = 1;
}
if (itemTemplate.InventoryType >= MAX_INVTYPE)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong InventoryType value ({})", entry, itemTemplate.InventoryType);
itemTemplate.InventoryType = INVTYPE_NON_EQUIP;
}
if (itemTemplate.RequiredSkill >= MAX_SKILL_TYPE)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong RequiredSkill value ({})", entry, itemTemplate.RequiredSkill);
@@ -3118,12 +3152,6 @@ void ObjectMgr::LoadItemTemplates()
if (itemTemplate.LockID && !sLockStore.LookupEntry(itemTemplate.LockID))
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong LockID ({})", entry, itemTemplate.LockID);
if (itemTemplate.Sheath >= MAX_SHEATHETYPE)
{
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Sheath ({})", entry, itemTemplate.Sheath);
itemTemplate.Sheath = SHEATHETYPE_NONE;
}
if (itemTemplate.RandomProperty)
{
// To be implemented later
@@ -9995,8 +10023,8 @@ void ObjectMgr::LoadGameObjectQuestItems()
{
uint32 oldMSTime = getMSTime();
// 0 1
QueryResult result = WorldDatabase.Query("SELECT GameObjectEntry, ItemId FROM gameobject_questitem ORDER BY Idx ASC");
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT GameObjectEntry, ItemId, Idx FROM gameobject_questitem ORDER BY Idx ASC");
if (!result)
{
@@ -10011,6 +10039,21 @@ void ObjectMgr::LoadGameObjectQuestItems()
uint32 entry = fields[0].Get<uint32>();
uint32 item = fields[1].Get<uint32>();
uint32 idx = fields[2].Get<uint32>();
GameObjectTemplate const* goInfo = GetGameObjectTemplate(entry);
if (!goInfo)
{
LOG_ERROR("sql.sql", "Table `gameobject_questitem` has data for nonexistent gameobject (entry: {}, idx: {}), skipped", entry, idx);
continue;
};
ItemEntry const* dbcData = sItemStore.LookupEntry(item);
if (!dbcData)
{
LOG_ERROR("sql.sql", "Table `gameobject_questitem` has nonexistent item (ID: {}) in gameobject (entry: {}, idx: {}), skipped", item, entry, idx);
continue;
};
_gameObjectQuestItemStore[entry].push_back(item);
@@ -10025,8 +10068,8 @@ void ObjectMgr::LoadCreatureQuestItems()
{
uint32 oldMSTime = getMSTime();
// 0 1
QueryResult result = WorldDatabase.Query("SELECT CreatureEntry, ItemId FROM creature_questitem ORDER BY Idx ASC");
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT CreatureEntry, ItemId, Idx FROM creature_questitem ORDER BY Idx ASC");
if (!result)
{
@@ -10041,6 +10084,21 @@ void ObjectMgr::LoadCreatureQuestItems()
uint32 entry = fields[0].Get<uint32>();
uint32 item = fields[1].Get<uint32>();
uint32 idx = fields[2].Get<uint32>();
CreatureTemplate const* creatureInfo = GetCreatureTemplate(entry);
if (!creatureInfo)
{
LOG_ERROR("sql.sql", "Table `creature_questitem` has data for nonexistent creature (entry: {}, idx: {}), skipped", entry, idx);
continue;
};
ItemEntry const* dbcData = sItemStore.LookupEntry(item);
if (!dbcData)
{
LOG_ERROR("sql.sql", "Table `creature_questitem` has nonexistent item (ID: {}) in creature (entry: {}, idx: {}), skipped", item, entry, idx);
continue;
};
_creatureQuestItemStore[entry].push_back(item);
@@ -2243,7 +2243,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact
// Get level from LFGDungeonEntry because the one from AreaTableEntry is not valid
// If area level is too big, do not add new taxi
if (lfgDungeon->minlevel > level)
if (lfgDungeon->MinLevel > level)
{
FillTaxiMask(field, 0);
continue;
+14 -4
View File
@@ -505,16 +505,26 @@ void InstanceScript::DoRespawnGameObject(ObjectGuid uiGuid, uint32 uiTimeToDespa
{
if (GameObject* go = instance->GetGameObject(uiGuid))
{
//not expect any of these should ever be handled
if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE || go->GetGoType() == GAMEOBJECT_TYPE_DOOR ||
go->GetGoType() == GAMEOBJECT_TYPE_BUTTON || go->GetGoType() == GAMEOBJECT_TYPE_TRAP)
return;
switch (go->GetGoType())
{
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_BUTTON:
case GAMEOBJECT_TYPE_TRAP:
case GAMEOBJECT_TYPE_FISHINGNODE:
// not expect any of these should ever be handled
LOG_ERROR("scripts", "InstanceScript: DoRespawnGameObject can't respawn gameobject entry {}, because type is {}.", go->GetEntry(), go->GetGoType());
return;
default:
break;
}
if (go->isSpawned())
return;
go->SetRespawnTime(uiTimeToDespawn);
}
else
LOG_DEBUG("scripts", "InstanceScript: DoRespawnGameObject failed");
}
void InstanceScript::DoRespawnCreature(ObjectGuid guid, bool force)
@@ -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);
Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true, false);
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
}
+3 -3
View File
@@ -4928,11 +4928,11 @@ void Spell::WriteAmmoToPacket(WorldPacket* data)
{
if (uint32 item_id = m_caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i))
{
if (ItemTemplate const* itemEntry = sObjectMgr->GetItemTemplate(item_id))
if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
{
if (itemEntry->Class == ITEM_CLASS_WEAPON)
if (itemEntry->ClassID == ITEM_CLASS_WEAPON)
{
switch (itemEntry->SubClass)
switch (itemEntry->SubclassID)
{
case ITEM_SUBCLASS_WEAPON_THROWN:
ammoDisplayID = itemEntry->DisplayInfoID;
+35
View File
@@ -0,0 +1,35 @@
/*
* 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);
}
+7 -1
View File
@@ -24,15 +24,17 @@
#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
@@ -138,6 +140,7 @@ enum WorldBoolConfigs
CONFIG_AUTOBROADCAST,
CONFIG_ALLOW_TICKETS,
CONFIG_DELETE_CHARACTER_TICKET_TRACE,
CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
CONFIG_PRESERVE_CUSTOM_CHANNELS,
CONFIG_PDUMP_NO_PATHS,
CONFIG_PDUMP_NO_OVERWRITE,
@@ -515,10 +518,13 @@ 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;
+32
View File
@@ -1357,6 +1357,9 @@ void World::LoadConfigSettings(bool reload)
// Dungeon finder
_int_configs[CONFIG_LFG_OPTIONSMASK] = sConfigMgr->GetOption<int32>("DungeonFinder.OptionsMask", 5);
// DBC_ItemAttributes
_bool_configs[CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES] = sConfigMgr->GetOption<bool>("DBC.EnforceItemAttributes", true);
// Max instances per hour
_int_configs[CONFIG_MAX_INSTANCES_PER_HOUR] = sConfigMgr->GetOption<int32>("AccountInstancesPerHour", 5);
@@ -2062,6 +2065,8 @@ 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", " ");
@@ -2308,6 +2313,12 @@ 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)
{
@@ -3340,3 +3351,24 @@ 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,6 +28,7 @@
#include "QueryResult.h"
#include "SharedDefines.h"
#include "Timer.h"
#include "Unit.h"
#include <atomic>
#include <list>
#include <map>
@@ -70,6 +71,7 @@ enum WorldTimers
WUPDATE_PINGDB,
WUPDATE_5_SECS,
WUPDATE_WHO_LIST,
WUPDATE_DELAYED_DAMAGES,
WUPDATE_COUNT
};
@@ -153,6 +155,8 @@ public:
World();
~World() override;
std::list<DelayedDamage> _delayedDamages;
static World* instance();
static uint32 m_worldLoopCounter;
@@ -353,6 +357,10 @@ 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
@@ -222,7 +222,7 @@ public:
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (_dying && who->GetGUID() != me->GetGUID())
if (_dying && who && who->GetGUID() != me->GetGUID())
damage = 0;
if (me->HealthBelowPctDamaged(0, damage) && instance->GetData(DATA_BUG_TRIO_DEATH) < 2 && !_dying)
@@ -61,6 +61,7 @@ enum Texts
SAY_TIRION_INTRO_2 = 1,
SAY_TIRION_OUTRO_1 = 2,
SAY_TIRION_OUTRO_2 = 3,
SAY_TIRION_OUTRO_3 = 4,
// Terenas Menethil (outro)
SAY_TERENAS_OUTRO_1 = 0,
@@ -343,6 +344,7 @@ enum MiscData
{
LIGHT_SNOWSTORM = 2490,
LIGHT_SOULSTORM = 2508,
EQUIP_ASHBRINGER = 13262,
MUSIC_FROZEN_THRONE = 17457,
MUSIC_SPECIAL = 17458, // Summon Shambling Horror, Remorseless Winter, Quake, Summon Val'kyr Periodic, Harvest Soul, Vile Spirits
MUSIC_FURY_OF_FROSTMOURNE = 17459,
@@ -833,8 +835,7 @@ public:
_bFordringMustFallYell = true;
if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING)))
{
tirion->Yell("The Lich King must fall!", LANG_UNIVERSAL);
tirion->PlayDirectSound(17389);
tirion->AI()->Talk(SAY_TIRION_OUTRO_3);
}
}
}
@@ -1354,7 +1355,7 @@ public:
{
// remove glow on ashbringer and tirion
me->RemoveAllAuras();
SetEquipmentSlots(true);
SetEquipmentSlots(false, EQUIP_ASHBRINGER);
}
}
@@ -1595,7 +1596,7 @@ public:
lichKing->SetImmuneToNPC(false);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
me->RemoveAllAuras();
SetEquipmentSlots(true);
SetEquipmentSlots(false, EQUIP_ASHBRINGER);
me->Attack(lichKing, true);
me->GetMotionMaster()->MovePoint(0, 512.16f, -2120.25f, 840.86f);
}
@@ -74,6 +74,8 @@ struct boss_murmur : public BossAI
void CastSupressionOOC()
{
me->m_Events.CancelEventGroup(GROUP_OOC_CAST);
me->m_Events.AddEventAtOffset([this] {
if (me->FindNearestCreature(NPC_CABAL_SPELLBINDER, 35.0f))
{
@@ -125,8 +127,13 @@ struct boss_murmur : public BossAI
}
}
void JustEngagedWith(Unit* /*who*/) override
void JustEngagedWith(Unit* who) override
{
if (!who->IsInCombatWith(me))
{
return;
}
_JustEngagedWith();
scheduler.Schedule(28s, [this](TaskContext context)
@@ -102,7 +102,6 @@ public:
{
if (Creature* broggok = instance->GetCreature(DATA_BROGGOK))
{
instance->SetData(DATA_BROGGOK, IN_PROGRESS);
broggok->AI()->DoAction(ACTION_PREPARE_BROGGOK);
}
}
@@ -30,13 +30,15 @@ DoorData const doorData[] =
ObjectData const gameobjectData[] =
{
{ GO_BROGGOK_DOOR_REAR, DATA_BROGGOK_REAR_DOOR },
{ GO_BROGGOK_LEVER, DATA_BROGGOK_LEVER }
{ GO_BROGGOK_LEVER, DATA_BROGGOK_LEVER },
{ 0, 0, }
};
ObjectData const creatureData[] =
{
{ NPC_BROGGOK, DATA_BROGGOK },
{ NPC_KELIDAN, DATA_KELIDAN }
{ NPC_KELIDAN, DATA_KELIDAN },
{ 0, 0 }
};
class instance_blood_furnace : public InstanceMapScript
+33 -18
View File
@@ -1163,6 +1163,18 @@ struct HolidaysEntry
//uint32 flags; // 54 m_flags (0 = Darkmoon Faire, Fishing Contest and Wotlk Launch, rest is 1)
};
struct ItemEntry
{
uint32 ID; // 0
uint32 ClassID; // 1
uint32 SubclassID; // 2
int32 SoundOverrideSubclassID; // 3
int32 Material; // 4
uint32 DisplayInfoID; // 5
uint32 InventoryType; // 6
uint32 SheatheType; // 7
};
struct ItemBagFamilyEntry
{
uint32 ID; // 0
@@ -1258,25 +1270,28 @@ struct ItemSetEntry
struct LFGDungeonEntry
{
uint32 ID; // 0
char const* name[16]; // 1-17 Name lang
uint32 minlevel; // 18
uint32 maxlevel; // 19
uint32 reclevel; // 20
uint32 recminlevel; // 21
uint32 recmaxlevel; // 22
int32 map; // 23
uint32 difficulty; // 24
uint32 flags; // 25
uint32 type; // 26
//uint32 unk; // 27
//char const* iconname; // 28
uint32 expansion; // 29
//uint32 unk4; // 30
uint32 grouptype; // 31
//char const* desc[16]; // 32-47 Description
uint32 ID; // 0
char const* Name[16]; // 1-16
//uint32 Name_lang_mask; // 17
uint32 MinLevel; // 18
uint32 MaxLevel; // 19
uint32 TargetLevel; // 20
uint32 TargetLevelMin; // 21
uint32 TargetLevelMax; // 22
uint32 MapID; // 23
uint32 Difficulty; // 24
uint32 Flags; // 25
uint32 TypeID; // 26
//int32 Faction; // 27
//char const* TextureFilename; // 28
uint32 ExpansionLevel; // 29
//uint32 OrderIndex; // 30
uint32 GroupID; // 31
//char const* Description[16]; // 32-47
//uint32 Description_lang_mask; // 48
// Helpers
[[nodiscard]] uint32 Entry() const { return ID + (type << 24); }
[[nodiscard]] uint32 Entry() const { return ID + (TypeID << 24); }
};
struct LightEntry
+1
View File
@@ -70,6 +70,7 @@ char constexpr GtOCTRegenHPfmt[] = "df";
char constexpr GtRegenHPPerSptfmt[] = "df";
char constexpr GtRegenMPPerSptfmt[] = "df";
char constexpr Holidaysfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix";
char constexpr Itemfmt[] = "niiiiiii";
char constexpr ItemBagFamilyfmt[] = "nxxxxxxxxxxxxxxxxx";
char constexpr ItemDisplayTemplateEntryfmt[] = "nxxxxsxxxxxxxxxxxxxxxxxxx";
//char constexpr ItemCondExtCostsEntryfmt[] = "xiii";