diff options
-rw-r--r-- | sql/updates/hotfixes/master/2021_11_18_00_hotfixes.sql | 94 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.cpp | 21 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.h | 9 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2LoadInfo.h | 95 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 15 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 3 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 63 | ||||
-rw-r--r-- | src/server/game/DataStores/DBCEnums.h | 15 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/SharedDefines.h | 2 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 16 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 36 |
12 files changed, 368 insertions, 5 deletions
diff --git a/sql/updates/hotfixes/master/2021_11_18_00_hotfixes.sql b/sql/updates/hotfixes/master/2021_11_18_00_hotfixes.sql new file mode 100644 index 00000000000..01af175f5cb --- /dev/null +++ b/sql/updates/hotfixes/master/2021_11_18_00_hotfixes.sql @@ -0,0 +1,94 @@ +-- +-- Table structure for table `spell_visual` +-- +DROP TABLE IF EXISTS `spell_visual`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `spell_visual` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `MissileCastOffset1` float NOT NULL DEFAULT '0', + `MissileCastOffset2` float NOT NULL DEFAULT '0', + `MissileCastOffset3` float NOT NULL DEFAULT '0', + `MissileImpactOffset1` float NOT NULL DEFAULT '0', + `MissileImpactOffset2` float NOT NULL DEFAULT '0', + `MissileImpactOffset3` float NOT NULL DEFAULT '0', + `AnimEventSoundID` int(10) unsigned NOT NULL DEFAULT '0', + `Flags` int(11) NOT NULL DEFAULT '0', + `MissileAttachment` tinyint(4) NOT NULL DEFAULT '0', + `MissileDestinationAttachment` tinyint(4) NOT NULL DEFAULT '0', + `MissileCastPositionerID` int(10) unsigned NOT NULL DEFAULT '0', + `MissileImpactPositionerID` int(10) unsigned NOT NULL DEFAULT '0', + `MissileTargetingKit` int(11) NOT NULL DEFAULT '0', + `HostileSpellVisualID` int(10) unsigned NOT NULL DEFAULT '0', + `CasterSpellVisualID` int(10) unsigned NOT NULL DEFAULT '0', + `SpellVisualMissileSetID` smallint(5) unsigned NOT NULL DEFAULT '0', + `DamageNumberDelay` smallint(5) unsigned NOT NULL DEFAULT '0', + `LowViolenceSpellVisualID` int(10) unsigned NOT NULL DEFAULT '0', + `RaidSpellVisualMissileSetID` int(10) unsigned NOT NULL DEFAULT '0', + `ReducedUnexpectedCameraMovementSpellVisualID` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `spell_visual_effect_name` +-- +DROP TABLE IF EXISTS `spell_visual_effect_name`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `spell_visual_effect_name` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `ModelFileDataID` int(11) NOT NULL DEFAULT '0', + `BaseMissileSpeed` float NOT NULL DEFAULT '0', + `Scale` float NOT NULL DEFAULT '0', + `MinAllowedScale` float NOT NULL DEFAULT '0', + `MaxAllowedScale` float NOT NULL DEFAULT '0', + `Alpha` float NOT NULL DEFAULT '0', + `Flags` int(10) unsigned NOT NULL DEFAULT '0', + `TextureFileDataID` int(11) NOT NULL DEFAULT '0', + `EffectRadius` float NOT NULL DEFAULT '0', + `Type` int(10) unsigned NOT NULL DEFAULT '0', + `GenericID` int(11) NOT NULL DEFAULT '0', + `RibbonQualityID` int(10) unsigned NOT NULL DEFAULT '0', + `DissolveEffectID` int(11) NOT NULL DEFAULT '0', + `ModelPosition` int(11) NOT NULL DEFAULT '0', + `Unknown901` tinyint(4) NOT NULL DEFAULT '0', + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `spell_visual_missile` +-- +DROP TABLE IF EXISTS `spell_visual_missile`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `spell_visual_missile` ( + `CastOffset1` float NOT NULL DEFAULT '0', + `CastOffset2` float NOT NULL DEFAULT '0', + `CastOffset3` float NOT NULL DEFAULT '0', + `ImpactOffset1` float NOT NULL DEFAULT '0', + `ImpactOffset2` float NOT NULL DEFAULT '0', + `ImpactOffset3` float NOT NULL DEFAULT '0', + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `SpellVisualEffectNameID` smallint(5) unsigned NOT NULL DEFAULT '0', + `SoundEntriesID` int(10) unsigned NOT NULL DEFAULT '0', + `Attachment` tinyint(4) NOT NULL DEFAULT '0', + `DestinationAttachment` tinyint(4) NOT NULL DEFAULT '0', + `CastPositionerID` smallint(5) unsigned NOT NULL DEFAULT '0', + `ImpactPositionerID` smallint(5) unsigned NOT NULL DEFAULT '0', + `FollowGroundHeight` int(11) NOT NULL DEFAULT '0', + `FollowGroundDropSpeed` int(10) unsigned NOT NULL DEFAULT '0', + `FollowGroundApproach` smallint(5) unsigned NOT NULL DEFAULT '0', + `Flags` int(10) unsigned NOT NULL DEFAULT '0', + `SpellMissileMotionID` smallint(5) unsigned NOT NULL DEFAULT '0', + `AnimKitID` int(10) unsigned NOT NULL DEFAULT '0', + `ClutterLevel` tinyint(4) NOT NULL DEFAULT '0', + `DecayTimeAfterImpact` int(11) NOT NULL DEFAULT '0', + `SpellVisualMissileSetID` int(10) unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 81669da1420..d88ecc71d53 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -1529,6 +1529,27 @@ void HotfixDatabaseConnection::DoPrepareStatements() " FROM spell_totems WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_SPELL_TOTEMS, "SELECT MAX(ID) + 1 FROM spell_totems", CONNECTION_SYNCH); + // SpellVisual.db2 + PrepareStatement(HOTFIX_SEL_SPELL_VISUAL, "SELECT ID, MissileCastOffset1, MissileCastOffset2, MissileCastOffset3, MissileImpactOffset1, " + "MissileImpactOffset2, MissileImpactOffset3, AnimEventSoundID, Flags, MissileAttachment, MissileDestinationAttachment, " + "MissileCastPositionerID, MissileImpactPositionerID, MissileTargetingKit, HostileSpellVisualID, CasterSpellVisualID, SpellVisualMissileSetID, " + "DamageNumberDelay, LowViolenceSpellVisualID, RaidSpellVisualMissileSetID, ReducedUnexpectedCameraMovementSpellVisualID FROM spell_visual" + " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_SPELL_VISUAL, "SELECT MAX(ID) + 1 FROM spell_visual", CONNECTION_SYNCH); + + // SpellVisualEffectName.db2 + PrepareStatement(HOTFIX_SEL_SPELL_VISUAL_EFFECT_NAME, "SELECT ID, ModelFileDataID, BaseMissileSpeed, Scale, MinAllowedScale, MaxAllowedScale, " + "Alpha, Flags, TextureFileDataID, EffectRadius, Type, GenericID, RibbonQualityID, DissolveEffectID, ModelPosition, Unknown901" + " FROM spell_visual_effect_name WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_SPELL_VISUAL_EFFECT_NAME, "SELECT MAX(ID) + 1 FROM spell_visual_effect_name", CONNECTION_SYNCH); + + // SpellVisualMissile.db2 + PrepareStatement(HOTFIX_SEL_SPELL_VISUAL_MISSILE, "SELECT CastOffset1, CastOffset2, CastOffset3, ImpactOffset1, ImpactOffset2, ImpactOffset3, ID, " + "SpellVisualEffectNameID, SoundEntriesID, Attachment, DestinationAttachment, CastPositionerID, ImpactPositionerID, FollowGroundHeight, " + "FollowGroundDropSpeed, FollowGroundApproach, Flags, SpellMissileMotionID, AnimKitID, ClutterLevel, DecayTimeAfterImpact, " + "SpellVisualMissileSetID FROM spell_visual_missile WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_SPELL_VISUAL_MISSILE, "SELECT MAX(ID) + 1 FROM spell_visual_missile", CONNECTION_SYNCH); + // SpellVisualKit.db2 PrepareStatement(HOTFIX_SEL_SPELL_VISUAL_KIT, "SELECT ID, FallbackPriority, FallbackSpellVisualKitId, DelayMin, DelayMax, Flags1, Flags2" " FROM spell_visual_kit WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index 73aa6c24e1c..ca7cfae3154 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -886,6 +886,15 @@ enum HotfixDatabaseStatements : uint32 HOTFIX_SEL_SPELL_TOTEMS, HOTFIX_SEL_SPELL_TOTEMS_MAX_ID, + HOTFIX_SEL_SPELL_VISUAL, + HOTFIX_SEL_SPELL_VISUAL_MAX_ID, + + HOTFIX_SEL_SPELL_VISUAL_EFFECT_NAME, + HOTFIX_SEL_SPELL_VISUAL_EFFECT_NAME_MAX_ID, + + HOTFIX_SEL_SPELL_VISUAL_MISSILE, + HOTFIX_SEL_SPELL_VISUAL_MISSILE_MAX_ID, + HOTFIX_SEL_SPELL_VISUAL_KIT, HOTFIX_SEL_SPELL_VISUAL_KIT_MAX_ID, diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h index 1d4b28ccfaa..2ddfdadf5ef 100644 --- a/src/server/game/DataStores/DB2LoadInfo.h +++ b/src/server/game/DataStores/DB2LoadInfo.h @@ -5846,6 +5846,101 @@ struct SpellTotemsLoadInfo } }; +struct SpellVisualLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { false, FT_FLOAT, "MissileCastOffset1" }, + { false, FT_FLOAT, "MissileCastOffset2" }, + { false, FT_FLOAT, "MissileCastOffset3" }, + { false, FT_FLOAT, "MissileImpactOffset1" }, + { false, FT_FLOAT, "MissileImpactOffset2" }, + { false, FT_FLOAT, "MissileImpactOffset3" }, + { false, FT_INT, "AnimEventSoundID" }, + { true, FT_INT, "Flags" }, + { true, FT_BYTE, "MissileAttachment" }, + { true, FT_BYTE, "MissileDestinationAttachment" }, + { false, FT_INT, "MissileCastPositionerID" }, + { false, FT_INT, "MissileImpactPositionerID" }, + { true, FT_INT, "MissileTargetingKit" }, + { false, FT_INT, "HostileSpellVisualID" }, + { false, FT_INT, "CasterSpellVisualID" }, + { false, FT_SHORT, "SpellVisualMissileSetID" }, + { false, FT_SHORT, "DamageNumberDelay" }, + { false, FT_INT, "LowViolenceSpellVisualID" }, + { false, FT_INT, "RaidSpellVisualMissileSetID" }, + { true, FT_INT, "ReducedUnexpectedCameraMovementSpellVisualID" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, SpellVisualMeta::Instance(), HOTFIX_SEL_SPELL_VISUAL); + return &loadInfo; + } +}; + +struct SpellVisualEffectNameLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { true, FT_INT, "ModelFileDataID" }, + { false, FT_FLOAT, "BaseMissileSpeed" }, + { false, FT_FLOAT, "Scale" }, + { false, FT_FLOAT, "MinAllowedScale" }, + { false, FT_FLOAT, "MaxAllowedScale" }, + { false, FT_FLOAT, "Alpha" }, + { false, FT_INT, "Flags" }, + { true, FT_INT, "TextureFileDataID" }, + { false, FT_FLOAT, "EffectRadius" }, + { false, FT_INT, "Type" }, + { true, FT_INT, "GenericID" }, + { false, FT_INT, "RibbonQualityID" }, + { true, FT_INT, "DissolveEffectID" }, + { true, FT_INT, "ModelPosition" }, + { true, FT_BYTE, "Unknown901" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, SpellVisualEffectNameMeta::Instance(), HOTFIX_SEL_SPELL_VISUAL_EFFECT_NAME); + return &loadInfo; + } +}; + +struct SpellVisualMissileLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_FLOAT, "CastOffset1" }, + { false, FT_FLOAT, "CastOffset2" }, + { false, FT_FLOAT, "CastOffset3" }, + { false, FT_FLOAT, "ImpactOffset1" }, + { false, FT_FLOAT, "ImpactOffset2" }, + { false, FT_FLOAT, "ImpactOffset3" }, + { false, FT_INT, "ID" }, + { false, FT_SHORT, "SpellVisualEffectNameID" }, + { false, FT_INT, "SoundEntriesID" }, + { true, FT_BYTE, "Attachment" }, + { true, FT_BYTE, "DestinationAttachment" }, + { false, FT_SHORT, "CastPositionerID" }, + { false, FT_SHORT, "ImpactPositionerID" }, + { true, FT_INT, "FollowGroundHeight" }, + { false, FT_INT, "FollowGroundDropSpeed" }, + { false, FT_SHORT, "FollowGroundApproach" }, + { false, FT_INT, "Flags" }, + { false, FT_SHORT, "SpellMissileMotionID" }, + { false, FT_INT, "AnimKitID" }, + { true, FT_BYTE, "ClutterLevel" }, + { true, FT_INT, "DecayTimeAfterImpact" }, + { false, FT_INT, "SpellVisualMissileSetID" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, SpellVisualMissileMeta::Instance(), HOTFIX_SEL_SPELL_VISUAL_MISSILE); + return &loadInfo; + } +}; + struct SpellVisualKitLoadInfo { static DB2LoadInfo const* Instance() diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 2f629d2d2fe..21780c9935c 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -302,6 +302,9 @@ DB2Storage<SpellShapeshiftEntry> sSpellShapeshiftStore("SpellShap DB2Storage<SpellShapeshiftFormEntry> sSpellShapeshiftFormStore("SpellShapeshiftForm.db2", SpellShapeshiftFormLoadInfo::Instance()); DB2Storage<SpellTargetRestrictionsEntry> sSpellTargetRestrictionsStore("SpellTargetRestrictions.db2", SpellTargetRestrictionsLoadInfo::Instance()); DB2Storage<SpellTotemsEntry> sSpellTotemsStore("SpellTotems.db2", SpellTotemsLoadInfo::Instance()); +DB2Storage<SpellVisualEntry> sSpellVisualStore("SpellVisual.db2", SpellVisualLoadInfo::Instance()); +DB2Storage<SpellVisualEffectNameEntry> sSpellVisualEffectNameStore("SpellVisualEffectName.db2", SpellVisualEffectNameLoadInfo::Instance()); +DB2Storage<SpellVisualMissileEntry> sSpellVisualMissileStore("SpellVisualMissile.db2", SpellVisualMissileLoadInfo::Instance()); DB2Storage<SpellVisualKitEntry> sSpellVisualKitStore("SpellVisualKit.db2", SpellVisualKitLoadInfo::Instance()); DB2Storage<SpellXSpellVisualEntry> sSpellXSpellVisualStore("SpellXSpellVisual.db2", SpellXSpellVisualLoadInfo::Instance()); DB2Storage<SummonPropertiesEntry> sSummonPropertiesStore("SummonProperties.db2", SummonPropertiesLoadInfo::Instance()); @@ -476,6 +479,7 @@ namespace std::unordered_set<std::pair<int32, uint32>> _specsBySpecSet; std::unordered_set<uint8> _spellFamilyNames; SpellProcsPerMinuteModContainer _spellProcsPerMinuteMods; + std::unordered_map<int32, std::vector<SpellVisualMissileEntry const*>> _spellVisualMissilesBySet; TalentsByPosition _talentsByPosition; ToyItemIdsContainer _toys; std::unordered_map<uint32, TransmogIllusionEntry const*> _transmogIllusionsByEnchantmentId; @@ -870,6 +874,9 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul LOAD_DB2(sSpellShapeshiftFormStore); LOAD_DB2(sSpellTargetRestrictionsStore); LOAD_DB2(sSpellTotemsStore); + LOAD_DB2(sSpellVisualStore); + LOAD_DB2(sSpellVisualEffectNameStore); + LOAD_DB2(sSpellVisualMissileStore); LOAD_DB2(sSpellVisualKitStore); LOAD_DB2(sSpellXSpellVisualStore); LOAD_DB2(sSummonPropertiesStore); @@ -1361,6 +1368,9 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul for (SpellProcsPerMinuteModEntry const* ppmMod : sSpellProcsPerMinuteModStore) _spellProcsPerMinuteMods[ppmMod->SpellProcsPerMinuteID].push_back(ppmMod); + for (SpellVisualMissileEntry const* spellVisualMissile : sSpellVisualMissileStore) + _spellVisualMissilesBySet[spellVisualMissile->SpellVisualMissileSetID].push_back(spellVisualMissile); + for (TalentEntry const* talentInfo : sTalentStore) { ASSERT(talentInfo->ClassID < MAX_CLASSES); @@ -2972,6 +2982,11 @@ std::vector<SpellProcsPerMinuteModEntry const*> DB2Manager::GetSpellProcsPerMinu return std::vector<SpellProcsPerMinuteModEntry const*>(); } +std::vector<SpellVisualMissileEntry const*> const* DB2Manager::GetSpellVisualMissiles(int32 spellVisualMissileSetId) const +{ + return Trinity::Containers::MapGetValuePtr(_spellVisualMissilesBySet, spellVisualMissileSetId); +} + std::vector<TalentEntry const*> const& DB2Manager::GetTalentsByPosition(uint32 class_, uint32 tier, uint32 column) const { return _talentsByPosition[class_][tier][column]; diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index cd8e074fb7a..8a652478c06 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -225,6 +225,8 @@ TC_GAME_API extern DB2Storage<SpellShapeshiftEntry> sSpellShapes TC_GAME_API extern DB2Storage<SpellShapeshiftFormEntry> sSpellShapeshiftFormStore; TC_GAME_API extern DB2Storage<SpellTargetRestrictionsEntry> sSpellTargetRestrictionsStore; TC_GAME_API extern DB2Storage<SpellTotemsEntry> sSpellTotemsStore; +TC_GAME_API extern DB2Storage<SpellVisualEntry> sSpellVisualStore; +TC_GAME_API extern DB2Storage<SpellVisualEffectNameEntry> sSpellVisualEffectNameStore; TC_GAME_API extern DB2Storage<SpellVisualKitEntry> sSpellVisualKitStore; TC_GAME_API extern DB2Storage<SpellXSpellVisualEntry> sSpellXSpellVisualStore; TC_GAME_API extern DB2Storage<SummonPropertiesEntry> sSummonPropertiesStore; @@ -449,6 +451,7 @@ public: bool IsSpecSetMember(int32 specSetId, uint32 specId) const; static bool IsValidSpellFamiliyName(SpellFamilyNames family); std::vector<SpellProcsPerMinuteModEntry const*> GetSpellProcsPerMinuteMods(uint32 spellprocsPerMinuteId) const; + std::vector<SpellVisualMissileEntry const*> const* GetSpellVisualMissiles(int32 spellVisualMissileSetId) const; std::vector<TalentEntry const*> const& GetTalentsByPosition(uint32 class_, uint32 tier, uint32 column) const; static bool IsTotemCategoryCompatibleWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId); bool IsToyItem(uint32 toy) const; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 6742d4f893c..7a3e476542e 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -3548,6 +3548,69 @@ struct SpellTotemsEntry int32 Totem[MAX_SPELL_TOTEMS]; }; +struct SpellVisualEntry +{ + uint32 ID; + float MissileCastOffset[3]; + float MissileImpactOffset[3]; + uint32 AnimEventSoundID; + int32 Flags; + int8 MissileAttachment; + int8 MissileDestinationAttachment; + uint32 MissileCastPositionerID; + uint32 MissileImpactPositionerID; + int32 MissileTargetingKit; + uint32 HostileSpellVisualID; + uint32 CasterSpellVisualID; + uint16 SpellVisualMissileSetID; + uint16 DamageNumberDelay; + uint32 LowViolenceSpellVisualID; + uint32 RaidSpellVisualMissileSetID; + int32 ReducedUnexpectedCameraMovementSpellVisualID; +}; + +struct SpellVisualEffectNameEntry +{ + uint32 ID; + int32 ModelFileDataID; + float BaseMissileSpeed; + float Scale; + float MinAllowedScale; + float MaxAllowedScale; + float Alpha; + uint32 Flags; + int32 TextureFileDataID; + float EffectRadius; + uint32 Type; + int32 GenericID; + uint32 RibbonQualityID; + int32 DissolveEffectID; + int32 ModelPosition; + int8 Unknown901; +}; + +struct SpellVisualMissileEntry +{ + float CastOffset[3]; + float ImpactOffset[3]; + uint32 ID; + uint16 SpellVisualEffectNameID; + uint32 SoundEntriesID; + int8 Attachment; + int8 DestinationAttachment; + uint16 CastPositionerID; + uint16 ImpactPositionerID; + int32 FollowGroundHeight; + uint32 FollowGroundDropSpeed; + uint16 FollowGroundApproach; + uint32 Flags; + uint16 SpellMissileMotionID; + uint32 AnimKitID; + int8 ClutterLevel; + int32 DecayTimeAfterImpact; + uint32 SpellVisualMissileSetID; +}; + struct SpellVisualKitEntry { uint32 ID; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 26feffc2ac2..5f752cfe715 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -1493,6 +1493,21 @@ enum class SpellShapeshiftFormFlags : int32 DEFINE_ENUM_FLAG(SpellShapeshiftFormFlags); +enum class SpellVisualEffectNameType : uint32 +{ + Model = 0, + Item = 1, + Creature = 2, + UnitItemMainHand = 3, + UnitItemOffHand = 4, + UnitItemRanged = 5, + UnitAmmoBasic = 6, + UnitAmmoPreferred = 7, + UnitItemMainHandIgnoreDisarmed = 8, + UnitItemOffHandIgnoreDisarmed = 9, + UnitItemRangedIgnoreDisarmed = 10 +}; + #define TaxiMaskSize 339 typedef std::array<uint8, TaxiMaskSize> TaxiMask; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 4ffbbf36085..470109e3e93 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -769,7 +769,7 @@ enum SpellAttr10 : uint32 { SPELL_ATTR10_UNK0 = 0x00000001, // TITLE Unknown attribute 0@Attr10 SPELL_ATTR10_UNK1 = 0x00000002, // TITLE Unknown attribute 1@Attr10 - SPELL_ATTR10_UNK2 = 0x00000004, // TITLE Unknown attribute 2@Attr10 + SPELL_ATTR10_USES_RANGED_SLOT_COSMETIC_ONLY = 0x00000004, // TITLE Uses Ranged Slot (Cosmetic Only) SPELL_ATTR10_UNK3 = 0x00000008, // TITLE Unknown attribute 3@Attr10 SPELL_ATTR10_WATER_SPOUT = 0x00000010, // TITLE NPC Knockback - ignore doors SPELL_ATTR10_UNK5 = 0x00000020, // TITLE Unknown attribute 5@Attr10 diff --git a/src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp b/src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp index 4c9293a97cf..df44e6cce30 100644 --- a/src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp +++ b/src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp @@ -1017,7 +1017,7 @@ TC_API_EXPORT EnumText EnumUtils<SpellAttr10>::ToString(SpellAttr10 value) { case SPELL_ATTR10_UNK0: return { "SPELL_ATTR10_UNK0", "Unknown attribute 0@Attr10", "" }; case SPELL_ATTR10_UNK1: return { "SPELL_ATTR10_UNK1", "Unknown attribute 1@Attr10", "" }; - case SPELL_ATTR10_UNK2: return { "SPELL_ATTR10_UNK2", "Unknown attribute 2@Attr10", "" }; + case SPELL_ATTR10_USES_RANGED_SLOT_COSMETIC_ONLY: return { "SPELL_ATTR10_USES_RANGED_SLOT_COSMETIC_ONLY", "Uses Ranged Slot (Cosmetic Only)", "" }; case SPELL_ATTR10_UNK3: return { "SPELL_ATTR10_UNK3", "Unknown attribute 3@Attr10", "" }; case SPELL_ATTR10_WATER_SPOUT: return { "SPELL_ATTR10_WATER_SPOUT", "NPC Knockback - ignore doors", "" }; case SPELL_ATTR10_UNK5: return { "SPELL_ATTR10_UNK5", "Unknown attribute 5@Attr10", "" }; @@ -1061,7 +1061,7 @@ TC_API_EXPORT SpellAttr10 EnumUtils<SpellAttr10>::FromIndex(size_t index) { case 0: return SPELL_ATTR10_UNK0; case 1: return SPELL_ATTR10_UNK1; - case 2: return SPELL_ATTR10_UNK2; + case 2: return SPELL_ATTR10_USES_RANGED_SLOT_COSMETIC_ONLY; case 3: return SPELL_ATTR10_UNK3; case 4: return SPELL_ATTR10_WATER_SPOUT; case 5: return SPELL_ATTR10_UNK5; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index cbcf5218f14..997327c3147 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4276,7 +4276,7 @@ void Spell::SendSpellStart() if (((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell) && !m_fromClient) castFlags |= CAST_FLAG_PENDING; - if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA)) + if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR10_USES_RANGED_SLOT_COSMETIC_ONLY) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA)) castFlags |= CAST_FLAG_PROJECTILE; if ((m_caster->GetTypeId() == TYPEID_PLAYER || @@ -4377,7 +4377,7 @@ void Spell::SendSpellGo() if (((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell) && !m_fromClient) castFlags |= CAST_FLAG_PENDING; - if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA)) + if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR10_USES_RANGED_SLOT_COSMETIC_ONLY) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA)) castFlags |= CAST_FLAG_PROJECTILE; // arrows/bullets visual if ((m_caster->GetTypeId() == TYPEID_PLAYER || @@ -4512,6 +4512,8 @@ void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo) } else if (Unit const* unitCaster = m_caster->ToUnit()) { + uint32 nonRangedAmmoDisplayID = 0; + uint32 nonRangedAmmoInventoryType = 0; for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i) { if (uint32 item_id = unitCaster->GetVirtualItemId(i)) @@ -4535,6 +4537,10 @@ void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo) ammoDisplayID = 5998; // is this need fixing? ammoInventoryType = INVTYPE_AMMO; break; + default: + nonRangedAmmoDisplayID = sDB2Manager.GetItemDisplayId(item_id, unitCaster->GetVirtualItemAppearanceMod(i)); + nonRangedAmmoInventoryType = itemEntry->InventoryType; + break; } if (ammoDisplayID) @@ -4543,6 +4549,12 @@ void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo) } } } + + if (!ammoDisplayID && !ammoInventoryType) + { + ammoDisplayID = nonRangedAmmoDisplayID; + ammoInventoryType = nonRangedAmmoInventoryType; + } } ammo.DisplayID = ammoDisplayID; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 1dea10aee2e..50dc075c120 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3223,6 +3223,42 @@ void SpellMgr::LoadSpellInfoCustomAttributes() } spellInfoMutable->_InitializeExplicitTargetMask(); + + if (spellInfoMutable->Speed > 0.0f) + { + auto visualNeedsAmmo = [](SpellXSpellVisualEntry const* spellXspellVisual) + { + SpellVisualEntry const* spellVisual = sSpellVisualStore.LookupEntry(spellXspellVisual->SpellVisualID); + if (!spellVisual) + return false; + + std::vector<SpellVisualMissileEntry const*> const* spellVisualMissiles = sDB2Manager.GetSpellVisualMissiles(spellVisual->SpellVisualMissileSetID); + if (!spellVisualMissiles) + return false; + + for (SpellVisualMissileEntry const* spellVisualMissile : *spellVisualMissiles) + { + SpellVisualEffectNameEntry const* spellVisualEffectName = sSpellVisualEffectNameStore.LookupEntry(spellVisualMissile->SpellVisualEffectNameID); + if (!spellVisualEffectName) + continue; + + SpellVisualEffectNameType type = SpellVisualEffectNameType(spellVisualEffectName->Type); + if (type == SpellVisualEffectNameType::UnitAmmoBasic || type == SpellVisualEffectNameType::UnitAmmoPreferred) + return true; + } + + return false; + }; + + for (SpellXSpellVisualEntry const* spellXspellVisual : spellInfoMutable->_visuals) + { + if (visualNeedsAmmo(spellXspellVisual)) + { + spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_NEEDS_AMMO_DATA; + break; + } + } + } } // addition for binary spells, omit spells triggering other spells |