diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 96479002ca..ffb979ea3f 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -93,6 +93,9 @@ static FactionTeamMap sFactionTeamMap; DBCStorage sFactionStore(FactionEntryfmt); DBCStorage sFactionTemplateStore(FactionTemplateEntryfmt); +// Used exclusively for data validation +DBCStorage sGameObjectArtKitStore(GameObjectArtKitfmt); + DBCStorage sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt); DBCStorage sGemPropertiesStore(GemPropertiesEntryfmt); DBCStorage sGlyphPropertiesStore(GlyphPropertiesfmt); @@ -138,10 +141,10 @@ DBCStorage sItemDamageTwoHandCasterStore(ItemDama DBCStorage sItemDamageWandStore(ItemDamagefmt); DBCStorage sItemDisenchantLootStore(ItemDisenchantLootfmt); //DBCStorage sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently -DBCStorage sItemLimitCategoryStore(ItemLimitCategoryEntryfmt); -DBCStorage sItemRandomPropertiesStore(ItemRandomPropertiesfmt); -DBCStorage sItemRandomSuffixStore(ItemRandomSuffixfmt); -DBCStorage sItemSetStore(ItemSetEntryfmt); +DBCStorage sItemLimitCategoryStore(ItemLimitCategoryEntryfmt); +DBCStorage sItemRandomPropertiesStore(ItemRandomPropertiesfmt); +DBCStorage sItemRandomSuffixStore(ItemRandomSuffixfmt); +DBCStorage sItemSetStore(ItemSetEntryfmt); DBCStorage sLFGDungeonStore(LFGDungeonEntryfmt); DBCStorage sLFGDungeonsGroupingMapStore(LFGDungeonsGroupingMapfmt); @@ -374,6 +377,7 @@ void LoadDBCStores(const std::string& dataPath) LOAD_DBC(sEmotesTextStore, "EmotesText.dbc");//15595 LOAD_DBC(sFactionStore, "Faction.dbc");//15595 LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc");//15595 + LOAD_DBC(sGameObjectArtKitStore, "GameObjectArtKit.dbc");//15595 LOAD_DBC(sGameObjectDisplayInfoStore, "GameObjectDisplayInfo.dbc");//15595 LOAD_DBC(sGemPropertiesStore, "GemProperties.dbc");//15595 LOAD_DBC(sGlyphPropertiesStore, "GlyphProperties.dbc");//15595 diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 17890ce2ec..54a9d9cc37 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -129,6 +129,7 @@ TC_GAME_API extern DBCStorage sEmotesTextStore; TC_GAME_API extern DBCStorage sEmotesTextSoundStore; TC_GAME_API extern DBCStorage sFactionStore; TC_GAME_API extern DBCStorage sFactionTemplateStore; +TC_GAME_API extern DBCStorage sGameObjectArtKitStore; TC_GAME_API extern DBCStorage sGameObjectDisplayInfoStore; TC_GAME_API extern DBCStorage sGemPropertiesStore; TC_GAME_API extern DBCStorage sGlyphPropertiesStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 71dd65a7a9..fda1d8dc65 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1195,6 +1195,13 @@ struct FactionTemplateEntry bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD) != 0; } }; +struct GameObjectArtKitEntry +{ + uint32 ID; // 0 + //char* TextureVariation[3] // 1-3 m_textureVariations[3] + //char* AttachModel[4] // 4-8 m_attachModels[4] +}; + struct GameObjectDisplayInfoEntry { uint32 Displayid; // 0 m_ID diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 89cf364d9b..68c0db6073 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -62,6 +62,7 @@ char const EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx"; char const EmotesTextSoundEntryfmt[] = "niiii"; char const FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixsxi"; char const FactionTemplateEntryfmt[] = "niiiiiiiiiiiii"; +char const GameObjectArtKitfmt[] = "nxxxxxxx"; char const GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffxxx"; char const GemPropertiesEntryfmt[] = "nixxii"; char const GlyphPropertiesfmt[] = "niii"; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 86678fa071..e9e25b1e4a 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1277,6 +1277,32 @@ void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = f m_cooldownTime = time_to_restore ? (GameTime::GetGameTimeMS() + time_to_restore) : 0; } +void GameObject::PlayAnimKit(int32 animKit) +{ + WorldPacket data(SMSG_GAME_OBJECT_ACTIVATE_ANIM_KIT, 4 + 2); + + ObjectGuid guid = GetGUID(); + data.WriteBit(guid[5]); + data.WriteBit(guid[1]); + data.WriteBit(guid[0]); + data.WriteBit(guid[4]); + data.WriteBit(guid[7]); + data.WriteBit(guid[2]); + data.WriteBit(guid[3]); + data.WriteBit(guid[6]); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[7]); + data << int32(animKit); + + SendMessageToSet(&data, nullptr); +} + void GameObject::SetGoArtKit(uint8 kit) { SetByteValue(GAMEOBJECT_BYTES_1, 2, kit); diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index a67f691c05..33735bc61d 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -169,6 +169,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject void SetGoAnimProgress(uint8 animprogress) { SetByteValue(GAMEOBJECT_BYTES_1, 3, animprogress); } static void SetGoArtKit(uint8 artkit, GameObject* go, ObjectGuid::LowType lowguid = 0); + void PlayAnimKit(int32 animKit); + void EnableCollision(bool enable); void Use(Unit* user); diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h index da3f89cc71..7b6373a6e5 100644 --- a/src/server/game/Entities/GameObject/GameObjectData.h +++ b/src/server/game/Entities/GameObject/GameObjectData.h @@ -22,10 +22,11 @@ #include "SharedDefines.h" #include "SpawnData.h" #include "WorldPacket.h" + +#include #include #include - #define MAX_GAMEOBJECT_QUEST_ITEMS 6 // from `gameobject_template` @@ -597,6 +598,7 @@ struct GameObjectTemplateAddon uint32 flags; uint32 mingold; uint32 maxgold; + std::array artKits; }; struct GameObjectLocale @@ -634,4 +636,47 @@ struct GameObjectData : public SpawnData uint8 artKit = 0; }; +enum class GameObjectActions : uint32 +{ + // Name from client executable // Comments + None, // -NONE- + AnimateCustom0, // Animate Custom0 + AnimateCustom1, // Animate Custom1 + AnimateCustom2, // Animate Custom2 + AnimateCustom3, // Animate Custom3 + Disturb, // Disturb // Triggers trap + Unlock, // Unlock // Resets GO_FLAG_LOCKED + Lock, // Lock // Sets GO_FLAG_LOCKED + Open, // Open // Sets GO_STATE_ACTIVE + OpenAndUnlock, // Open + Unlock // Sets GO_STATE_ACTIVE and resets GO_FLAG_LOCKED + Close, // Close // Sets GO_STATE_READY + ToggleOpen, // Toggle Open + Destroy, // Destroy // Sets GO_STATE_DESTROYED + Rebuild, // Rebuild // Resets from GO_STATE_DESTROYED + Creation, // Creation + Despawn, // Despawn + MakeInert, // Make Inert // Disables interactions + MakeActive, // Make Active // Enables interactions + CloseAndLock, // Close + Lock // Sets GO_STATE_READY and sets GO_FLAG_LOCKED + UseArtKit0, // Use ArtKit0 // 46904: 121 + UseArtKit1, // Use ArtKit1 // 36639: 81, 46903: 122 + UseArtKit2, // Use ArtKit2 + UseArtKit3, // Use ArtKit3 + SetTapList, // Set Tap List + GoTo1stFloor, // Go to 1st floor + GoTo2ndFloor, // Go to 2nd floor + GoTo3rdFloor, // Go to 3rd floor + GoTo4thFloor, // Go to 4th floor + GoTo5thFloor, // Go to 5th floor + GoTo6thFloor, // Go to 6th floor + GoTo7thFloor, // Go to 7th floor + GoTo8thFloor, // Go to 8th floor + GoTo9thFloor, // Go to 9th floor + GoTo10thFloor, // Go to 10th floor + UseArtKit4, // Use ArtKit4 + PlayAnimKit, // Play Anim Kit "%s" // MiscValueB -> Anim Kit ID + OpenAndPlayAnimKit, // Open + Play Anim Kit "%s" // MiscValueB -> Anim Kit ID + CloseAndPlayAnimKit, // Close + Play Anim Kit "%s" // MiscValueB -> Anim Kit ID +}; + #endif // GameObjectData_h__ diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 3cafb7e9bb..722d9686b7 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -7488,8 +7488,8 @@ void ObjectMgr::LoadGameObjectTemplateAddons() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 - QueryResult result = WorldDatabase.Query("SELECT entry, faction, flags, mingold, maxgold FROM gameobject_template_addon"); + // 0 1 2 3 4 5 6 7 8 9 + QueryResult result = WorldDatabase.Query("SELECT entry, faction, flags, mingold, maxgold, artkit0, artkit1, artkit2, artkit3, artkit4 FROM gameobject_template_addon"); if (!result) { @@ -7517,6 +7517,9 @@ void ObjectMgr::LoadGameObjectTemplateAddons() gameObjectAddon.mingold = fields[3].GetUInt32(); gameObjectAddon.maxgold = fields[4].GetUInt32(); + for (uint32 i = 0; i < gameObjectAddon.artKits.size(); ++i) + gameObjectAddon.artKits[i] = fields[5 + i].GetUInt32(); + // checks if (gameObjectAddon.faction && !sFactionTemplateStore.LookupEntry(gameObjectAddon.faction)) TC_LOG_ERROR("sql.sql", "GameObject (Entry: %u) has invalid faction (%u) defined in `gameobject_template_addon`.", entry, gameObjectAddon.faction); @@ -7534,6 +7537,20 @@ void ObjectMgr::LoadGameObjectTemplateAddons() } } + uint32 artKitIndex = 0; + for (uint32& artKitID : gameObjectAddon.artKits) + { + ++artKitIndex; + if (!artKitID) + continue; + + if (!sGameObjectArtKitStore.LookupEntry(artKitID)) + { + TC_LOG_ERROR("sql.sql", "GameObject (Entry: %u) has invalid `artkit%d` (%d) defined, set to zero instead.", entry, artKitIndex - 1, artKitID); + artKitID = 0; + } + } + ++count; } while (result->NextRow()); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 89c8fb1b83..db740ae07a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3729,7 +3729,7 @@ void Spell::EffectSummonPlayer(SpellEffIndex /*effIndex*/) unitTarget->ToPlayer()->SendSummonRequestFrom(m_caster); } -void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/) +void Spell::EffectActivateObject(SpellEffIndex effIndex) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -3737,12 +3737,105 @@ void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/) if (!gameObjTarget) return; - ScriptInfo activateCommand; - activateCommand.command = SCRIPT_COMMAND_ACTIVATE_OBJECT; + GameObjectActions action = GameObjectActions(m_spellInfo->Effects[effIndex].MiscValue); - // int32 unk = m_spellInfo->Effects[effIndex].MiscValue; // This is set for EffectActivateObject spells; needs research + switch (action) + { + case GameObjectActions::AnimateCustom0: + case GameObjectActions::AnimateCustom1: + case GameObjectActions::AnimateCustom2: + case GameObjectActions::AnimateCustom3: + gameObjTarget->SendCustomAnim(uint32(action) - uint32(GameObjectActions::AnimateCustom0)); + break; + case GameObjectActions::Disturb: // What's the difference with Open? + case GameObjectActions::Open: + gameObjTarget->Use(m_caster); + break; + case GameObjectActions::OpenAndUnlock: + gameObjTarget->UseDoorOrButton(0, false, m_caster); + // no break + case GameObjectActions::Unlock: + case GameObjectActions::Lock: + gameObjTarget->ApplyModFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED, action == GameObjectActions::Lock); + break; + case GameObjectActions::Close: + case GameObjectActions::Rebuild: + gameObjTarget->ResetDoorOrButton(); + break; + case GameObjectActions::Despawn: + gameObjTarget->DespawnOrUnsummon(); + break; + case GameObjectActions::MakeInert: + case GameObjectActions::MakeActive: + gameObjTarget->ApplyModFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE, action == GameObjectActions::MakeInert); + break; + case GameObjectActions::CloseAndLock: + gameObjTarget->ResetDoorOrButton(); + gameObjTarget->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + break; + case GameObjectActions::Destroy: + gameObjTarget->UseDoorOrButton(0, true, m_caster); + break; + case GameObjectActions::UseArtKit0: + case GameObjectActions::UseArtKit1: + case GameObjectActions::UseArtKit2: + case GameObjectActions::UseArtKit3: + case GameObjectActions::UseArtKit4: + { + GameObjectTemplateAddon const* templateAddon = gameObjTarget->GetTemplateAddon(); + + uint32 artKitIndex = uint32(action) - uint32(GameObjectActions::UseArtKit0); + // Non-sequential here + if (action == GameObjectActions::UseArtKit4) + artKitIndex = 4; + + uint32 artKitValue = 0; + if (templateAddon != nullptr) + artKitValue = templateAddon->artKits[artKitIndex]; + + if (artKitValue == 0) + TC_LOG_ERROR("sql.sql", "GameObject %d hit by spell %d needs `artkit%d` in `gameobject_template_addon`", gameObjTarget->GetEntry(), m_spellInfo->Id, artKitIndex); + else + gameObjTarget->SetGoArtKit(artKitValue); + + break; + } + case GameObjectActions::PlayAnimKit: + gameObjTarget->PlayAnimKit(m_spellInfo->Effects[effIndex].MiscValueB); + break; + break; + case GameObjectActions::OpenAndPlayAnimKit: + gameObjTarget->Use(m_caster); + gameObjTarget->PlayAnimKit(m_spellInfo->Effects[effIndex].MiscValueB); + break; + case GameObjectActions::CloseAndPlayAnimKit: + gameObjTarget->ResetDoorOrButton(); + gameObjTarget->PlayAnimKit(m_spellInfo->Effects[effIndex].MiscValueB); + break; + case GameObjectActions::GoTo1stFloor: + case GameObjectActions::GoTo2ndFloor: + case GameObjectActions::GoTo3rdFloor: + case GameObjectActions::GoTo4thFloor: + case GameObjectActions::GoTo5thFloor: + case GameObjectActions::GoTo6thFloor: + case GameObjectActions::GoTo7thFloor: + case GameObjectActions::GoTo8thFloor: + case GameObjectActions::GoTo9thFloor: + case GameObjectActions::GoTo10thFloor: + { + // Cast is kind of loose but it'll do + if (Transport* transportTarget = gameObjTarget->ToTransport()) + transportTarget->SetTransportState(GO_STATE_TRANSPORT_STOPPED, uint32_t(action) - uint32(GameObjectActions::GoTo1stFloor)); + break; + } + case GameObjectActions::None: + TC_LOG_FATAL("spell", "Spell %d has action type NONE in effect %d", m_spellInfo->Id, int32(effIndex)); + break; + default: + TC_LOG_ERROR("spell", "Spell %d has unhandled action %d in effect %d", m_spellInfo->Id, int32(action), int32(effIndex)); + break; + } - gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, 0, m_caster, gameObjTarget); } void Spell::EffectApplyGlyph(SpellEffIndex effIndex) diff --git a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp index 14e8f33dc4..0b6326fdc2 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp @@ -469,26 +469,8 @@ private: bool _firstGuardian; }; -// 45226 - Banging the Gong -class spell_banging_the_gong : public SpellScript -{ - PrepareSpellScript(spell_banging_the_gong); - - void Activate(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - GetHitGObj()->SendCustomAnim(0); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_banging_the_gong::Activate, EFFECT_1, SPELL_EFFECT_ACTIVATE_OBJECT); - } -}; - void AddSC_zulaman() { RegisterZulAamanCreatureAI(npc_zulaman_voljin); RegisterZulAamanCreatureAI(npc_zulaman_amanishi_guardian); - RegisterSpellScript(spell_banging_the_gong); } diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_temple_guardian_anhuur.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_temple_guardian_anhuur.cpp index 0173b39875..ecf4488a2a 100644 --- a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_temple_guardian_anhuur.cpp +++ b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_temple_guardian_anhuur.cpp @@ -422,33 +422,6 @@ class spell_anhuur_disable_beacon_beams : public SpellScript } }; -// 76599 - Activate Beacons -// 76600 - Deactivate Beacons -class spell_anhuur_handle_beacons : public SpellScript -{ - PrepareSpellScript(spell_anhuur_handle_beacons); - - void HandleEffect(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - int32 script = GetSpellInfo()->Effects[effIndex].MiscValue; - - GameObject* beacon = GetHitGObj(); - if (!beacon) - return; - - if (script == 16) // 16 => Disable - beacon->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - else if (script == 17) // 17 => Activate - beacon->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_anhuur_handle_beacons::HandleEffect, EFFECT_0, SPELL_EFFECT_ACTIVATE_OBJECT); - } -}; - class spell_anhuur_burning_light_forcecast : public SpellScript { PrepareSpellScript(spell_anhuur_burning_light_forcecast); @@ -493,7 +466,6 @@ void AddSC_boss_temple_guardian_anhuur() RegisterSpellScript(spell_anhuur_shield_of_light), RegisterAuraScript(spell_anhuur_reverberating_hymn); RegisterSpellScript(spell_anhuur_disable_beacon_beams); - RegisterSpellScript(spell_anhuur_handle_beacons); RegisterSpellScript(spell_anhuur_burning_light_forcecast); new achievement_i_hate_that_song(); }