diff --git a/data/sql/updates/pending_db_world/rev_1651816895816737900.sql b/data/sql/updates/pending_db_world/rev_1651816895816737900.sql new file mode 100644 index 000000000..0c5aa3292 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1651816895816737900.sql @@ -0,0 +1,56 @@ +-- +ALTER TABLE `gameobject_template_addon` + ADD COLUMN `artkit0` INT NOT NULL DEFAULT 0 AFTER `maxgold`, + ADD COLUMN `artkit1` INT NOT NULL DEFAULT 0 AFTER `artkit0`, + ADD COLUMN `artkit2` INT NOT NULL DEFAULT 0 AFTER `artkit1`, + ADD COLUMN `artkit3` INT NOT NULL DEFAULT 0 AFTER `artkit2`; + +DROP TABLE IF EXISTS `gameobjectartkit_dbc`; + +CREATE TABLE `gameobjectartkit_dbc` +( + `ID` INT NOT NULL DEFAULT 0, + `Texture_1` INT NOT NULL DEFAULT 0, + `Texture_2` INT NOT NULL DEFAULT 0, + `Texture_3` INT NOT NULL DEFAULT 0, + `Attach_Model_1` INT NOT NULL DEFAULT 0, + `Attach_Model_2` INT NOT NULL DEFAULT 0, + `Attach_Model_3` INT NOT NULL DEFAULT 0, + `Attach_Model_4` INT NOT NULL DEFAULT 0, + PRIMARY KEY (`ID`) +) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4; + +-- Note: All of these should be targetable by spells 46904 and 46903, but conditions are only set for Stormwind (damn Horde fanatics) +UPDATE `gameobject_template_addon` SET `artkit0` = 121, `artkit1` = 122 WHERE `entry` IN ( + 188352, -- Flame of Shattrath + 188129, -- Flame of Silvermoon + 188128, -- Flame of the Exodar + 181567, -- Flame of the Wetlands + 181566, -- Flame of Hillsbrad + 181565, -- Flame of Westfall + 181564, -- Flame of Silverpine + 181563, -- Flame of Darkshore + 181562, -- Flame of Stonetalon + 181561, -- Flame of Ashenvale + 181560, -- Flame of the Barrens + 181349, -- Flame of the Scholomance + 181348, -- Flame of Stratholme + 181347, -- Flame of Blackrock Spire + 181346, -- Flame of Dire Maul + 181345, -- Flame of the Hinterlands + 181344, -- Flame of the Blasted Lands + 181343, -- Flame of Un'Goro + 181342, -- Flame of Azshara + 181341, -- Flame of Searing Gorge + 181340, -- Flame of Winterspring + 181339, -- Flame of Silithus + 181338, -- Flame of the Plaguelands + 181337, -- Flame of Thunder Bluff + 181336, -- Flame of Orgrimmar + 181335, -- Flame of the Undercity + 181334, -- Flame of Darnassus + 181333, -- Flame of Ironforge + 181332 -- Flame of Stormwind +); + +DELETE FROM `spell_script_names` WHERE `ScriptName`= "spell_banging_the_gong"; diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index c396c3c1e..8952741db 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -76,6 +76,8 @@ static FactionTeamMap sFactionTeamMap; DBCStorage sFactionStore(FactionEntryfmt); DBCStorage sFactionTemplateStore(FactionTemplateEntryfmt); +DBCStorage sGameObjectArtKitStore(GameObjectArtKitfmt); + DBCStorage sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt); DBCStorage sGemPropertiesStore(GemPropertiesEntryfmt); DBCStorage sGlyphPropertiesStore(GlyphPropertiesfmt); @@ -294,6 +296,7 @@ void LoadDBCStores(const std::string& dataPath) LOAD_DBC(sEmotesTextStore, "EmotesText.dbc", "emotestext_dbc"); LOAD_DBC(sFactionStore, "Faction.dbc", "faction_dbc"); LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc", "factiontemplate_dbc"); + LOAD_DBC(sGameObjectArtKitStore, "GameObjectArtKit.dbc", "gameobjectartkit_dbc"); LOAD_DBC(sGameObjectDisplayInfoStore, "GameObjectDisplayInfo.dbc", "gameobjectdisplayinfo_dbc"); LOAD_DBC(sGemPropertiesStore, "GemProperties.dbc", "gemproperties_dbc"); LOAD_DBC(sGlyphPropertiesStore, "GlyphProperties.dbc", "glyphproperties_dbc"); diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index cd122c788..c9e70faee 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -104,6 +104,7 @@ extern DBCStorage sEmotesStore; extern DBCStorage sEmotesTextStore; extern DBCStorage sFactionStore; extern DBCStorage sFactionTemplateStore; +extern DBCStorage sGameObjectArtKitStore; extern DBCStorage sGameObjectDisplayInfoStore; extern DBCStorage sGemPropertiesStore; extern DBCStorage sGlyphPropertiesStore; diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index db8d05e08..bd8500f97 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -25,6 +25,7 @@ #include "Object.h" #include "SharedDefines.h" #include "Unit.h" +#include class GameObjectAI; class Transport; @@ -676,6 +677,7 @@ struct GameObjectTemplateAddon uint32 flags; uint32 mingold; uint32 maxgold; + std::array artKits = {}; }; // Benchmarked: Faster than std::map (insert/find) @@ -736,6 +738,35 @@ enum GOState #define MAX_GO_STATE 3 +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 +}; + // from `gameobject` struct GameObjectData { diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 32eda9fe7..81161064b 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -7183,8 +7183,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 + QueryResult result = WorldDatabase.Query("SELECT entry, faction, flags, mingold, maxgold, artkit0, artkit1, artkit2, artkit3 FROM gameobject_template_addon"); if (!result) { @@ -7215,6 +7215,21 @@ void ObjectMgr::LoadGameObjectTemplateAddons() gameObjectAddon.mingold = fields[3].Get(); gameObjectAddon.maxgold = fields[4].Get(); + for (uint32 i = 0; i < gameObjectAddon.artKits.size(); i++) + { + uint32 artKitID = fields[5 + i].Get(); + if (!artKitID) + continue; + + if (!sGameObjectArtKitStore.LookupEntry(artKitID)) + { + LOG_ERROR("sql.sql", "GameObject (Entry: {}) has invalid `artkit{}` {} defined, set to zero instead.", entry, i, artKitID); + continue; + } + + gameObjectAddon.artKits[i] = artKitID; + } + // checks if (gameObjectAddon.faction && !sFactionTemplateStore.LookupEntry(gameObjectAddon.faction)) LOG_ERROR("sql.sql", diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index c240f62c5..c329395ec 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4263,7 +4263,7 @@ void Spell::EffectSummonPlayer(SpellEffIndex /*effIndex*/) player->GetSession()->SendPacket(&data); } -void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/) +void Spell::EffectActivateObject(SpellEffIndex effIndex) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -4271,17 +4271,74 @@ void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/) if (!gameObjTarget) return; - Player* player = m_caster->GetTypeId() == TYPEID_PLAYER ? m_caster->ToPlayer() : m_caster->GetCharmerOrOwnerPlayerOrPlayerItself(); - gameObjTarget->Use(player ? player : m_caster); + GameObjectActions action = GameObjectActions(m_spellInfo->Effects[effIndex].MiscValue); + 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: + if (Unit* unitCaster = m_caster->ToUnit()) + gameObjTarget->Use(unitCaster); + break; + case GameObjectActions::OpenAndUnlock: + if (Unit* unitCaster = m_caster->ToUnit()) + gameObjTarget->UseDoorOrButton(0, false, unitCaster); + [[fallthrough]]; + 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: + if (Unit* unitCaster = m_caster->ToUnit()) + gameObjTarget->UseDoorOrButton(0, true, unitCaster); + break; + case GameObjectActions::UseArtKit0: + case GameObjectActions::UseArtKit1: + case GameObjectActions::UseArtKit2: + case GameObjectActions::UseArtKit3: + { + GameObjectTemplateAddon const* templateAddon = gameObjTarget->GetTemplateAddon(); - //ScriptInfo activateCommand; - //activateCommand.command = SCRIPT_COMMAND_ACTIVATE_OBJECT; + uint32 artKitIndex = uint32(action) - uint32(GameObjectActions::UseArtKit0); - // int32 unk = m_spellInfo->Effects[effIndex].MiscValue; // This is set for EffectActivateObject spells; needs research + uint32 artKitValue = 0; + if (templateAddon) + artKitValue = templateAddon->artKits[artKitIndex]; - // xinef: pass player to allow gossip scripts to work - // - //gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, 0, player ? player : m_caster, gameObjTarget); + if (artKitValue == 0) + LOG_ERROR("sql.sql", "GameObject {} hit by spell {} needs `artkit{}` in `gameobject_template_addon`", gameObjTarget->GetEntry(), m_spellInfo->Id, artKitIndex); + else + gameObjTarget->SetGoArtKit(artKitValue); + + break; + } + case GameObjectActions::None: + LOG_FATAL("spell", "Spell {} has action type NONE in effect {}", m_spellInfo->Id, int32(effIndex)); + break; + default: + LOG_ERROR("spell", "Spell {} has unhandled action {} in effect {}", m_spellInfo->Id, int32(action), int32(effIndex)); + break; + } } void Spell::EffectApplyGlyph(SpellEffIndex effIndex) diff --git a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp index aa883bb10..bd02ff14a 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp @@ -783,37 +783,9 @@ public: } }; -class spell_banging_the_gong : public SpellScriptLoader -{ -public: - spell_banging_the_gong() : SpellScriptLoader("spell_banging_the_gong") { } - - class spell_banging_the_gong_SpellScript : public SpellScript - { - PrepareSpellScript(spell_banging_the_gong_SpellScript); - - void Activate(SpellEffIndex index) - { - PreventHitDefaultEffect(index); - GetHitGObj()->SendCustomAnim(0); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_banging_the_gong_SpellScript::Activate, EFFECT_1, SPELL_EFFECT_ACTIVATE_OBJECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_banging_the_gong_SpellScript(); - } -}; - void AddSC_zulaman() { new npc_forest_frog(); new npc_zulaman_hostage(); new npc_harrison_jones(); - new spell_banging_the_gong(); } diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h index 7ee64900e..6b36051f7 100644 --- a/src/server/shared/DataStores/DBCStructure.h +++ b/src/server/shared/DataStores/DBCStructure.h @@ -979,6 +979,13 @@ struct FactionTemplateEntry [[nodiscard]] bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_ATTACK_PVP_ACTIVE_PLAYERS) != 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/shared/DataStores/DBCfmt.h b/src/server/shared/DataStores/DBCfmt.h index 7dc5867da..abd37d1e3 100644 --- a/src/server/shared/DataStores/DBCfmt.h +++ b/src/server/shared/DataStores/DBCfmt.h @@ -50,6 +50,7 @@ char constexpr EmotesEntryfmt[] = "nxxiiix"; char constexpr EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx"; char constexpr FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixssssssssssssssssxxxxxxxxxxxxxxxxxx"; char constexpr FactionTemplateEntryfmt[] = "niiiiiiiiiiiii"; +char constexpr GameObjectArtKitfmt[] = "nxxxxxxx"; char constexpr GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffx"; char constexpr GemPropertiesEntryfmt[] = "nixxi"; char constexpr GlyphPropertiesfmt[] = "niii";