Core/Spells: Implement SPELL_EFFECT_ACTIVATE_OBJECT. (#23) (#24997)

* Core/Spells: Implement SPELL_EFFECT_ACTIVATE_OBJECT. (#23)

Original research by @xvwyh.

# Conflicts:
#	src/server/game/DataStores/DBCStores.cpp
#	src/server/game/DataStores/DBCStructure.h
#	src/server/game/DataStores/DBCfmt.h
#	src/server/game/Entities/GameObject/GameObject.h
#	src/server/game/Entities/GameObject/GameObjectData.h
#	src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp
#	src/server/scripts/Kalimdor/HallsOfOrigination/boss_temple_guardian_anhuur.cpp

* Add missing sql update

* Fix some build errors

* Remove unused enum values

* Change artkits from 0-4 to 0-3

* Remove unused code

* Code review feedback

* Fix sql

* Remove artkit4 special case handling

* Default initialize artKits

* Code review feedback

* Split sql into structure and data files

Co-authored-by: Warpten <vertozor@gmail.com>
This commit is contained in:
Giacomo Pozzoni
2020-07-14 07:34:03 +00:00
committed by GitHub
parent 042b1abfd7
commit 203573db83
11 changed files with 173 additions and 35 deletions

View File

@@ -0,0 +1,6 @@
--
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`;

View File

@@ -0,0 +1,35 @@
--
-- 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";

View File

@@ -88,6 +88,9 @@ static FactionTeamMap sFactionTeamMap;
DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt);
DBCStorage <FactionTemplateEntry> sFactionTemplateStore(FactionTemplateEntryfmt);
// Used exclusively for data validation
DBCStorage <GameObjectArtKitEntry> sGameObjectArtKitStore(GameObjectArtKitfmt);
DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt);
DBCStorage <GemPropertiesEntry> sGemPropertiesStore(GemPropertiesEntryfmt);
DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore(GlyphPropertiesfmt);
@@ -311,6 +314,7 @@ void LoadDBCStores(const std::string& dataPath)
LOAD_DBC(sEmotesTextSoundStore, "EmotesTextSound.dbc");
LOAD_DBC(sFactionStore, "Faction.dbc");
LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc");
LOAD_DBC(sGameObjectArtKitStore, "GameObjectArtKit.dbc");
LOAD_DBC(sGameObjectDisplayInfoStore, "GameObjectDisplayInfo.dbc");
LOAD_DBC(sGemPropertiesStore, "GemProperties.dbc");
LOAD_DBC(sGlyphPropertiesStore, "GlyphProperties.dbc");

View File

@@ -122,6 +122,7 @@ TC_GAME_API extern DBCStorage <EmotesTextEntry> sEmotesTextStore;
TC_GAME_API extern DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore;
TC_GAME_API extern DBCStorage <FactionEntry> sFactionStore;
TC_GAME_API extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore;
TC_GAME_API extern DBCStorage <GameObjectArtKitEntry> sGameObjectArtKitStore;
TC_GAME_API extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore;
TC_GAME_API extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore;
TC_GAME_API extern DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore;

View File

@@ -169,6 +169,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
static void SetGoArtKit(uint8 artkit, GameObject* go, ObjectGuid::LowType lowguid = 0);
void SetPhaseMask(uint32 newPhaseMask, bool update) override;
void EnableCollision(bool enable);
void Use(Unit* user);

View File

@@ -22,6 +22,8 @@
#include "SharedDefines.h"
#include "SpawnData.h"
#include "WorldPacket.h"
#include <array>
#include <string>
#include <vector>
@@ -631,6 +633,7 @@ struct GameObjectTemplateAddon : public GameObjectOverride
{
uint32 Mingold;
uint32 Maxgold;
std::array<uint32, 4> artKits = {};
};
struct GameObjectLocale
@@ -669,4 +672,33 @@ 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
};
#endif // GameObjectData_h__

View File

@@ -7671,8 +7671,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)
{
@@ -7700,6 +7700,21 @@ void ObjectMgr::LoadGameObjectTemplateAddons()
gameObjectAddon.Mingold = fields[3].GetUInt32();
gameObjectAddon.Maxgold = fields[4].GetUInt32();
for (uint32 i = 0; i < gameObjectAddon.artKits.size(); ++i)
{
uint32 artKitID = fields[5 + i].GetUInt32();
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, i, artKitID);
continue;
}
gameObjectAddon.artKits[i] = artKitID;
}
// 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);

View File

@@ -3733,7 +3733,7 @@ void Spell::EffectSummonPlayer(SpellEffIndex /*effIndex*/)
unitTarget->ToPlayer()->SendSummonRequestFrom(unitCaster);
}
void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/)
void Spell::EffectActivateObject(SpellEffIndex effIndex)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
@@ -3741,12 +3741,76 @@ 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:
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();
uint32 artKitIndex = uint32(action) - uint32(GameObjectActions::UseArtKit0);
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::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)

View File

@@ -349,37 +349,9 @@ class npc_harrison_jones : public CreatureScript
}
};
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_zulaman_hostage();
new npc_harrison_jones();
new spell_banging_the_gong();
}

View File

@@ -731,6 +731,13 @@ struct FactionTemplateEntry
bool IsContestedGuardFaction() const { return (Flags & 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 ID; // 0

View File

@@ -56,6 +56,7 @@ char constexpr EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx";
char constexpr EmotesTextSoundEntryfmt[] = "niiii";
char constexpr FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffiissssssssssssssssxxxxxxxxxxxxxxxxxx";
char constexpr FactionTemplateEntryfmt[] = "niiiiiiiiiiiii";
char constexpr GameObjectArtKitfmt[] = "nxxxxxxx";
char constexpr GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffx";
char constexpr GemPropertiesEntryfmt[] = "nixxi";
char constexpr GlyphPropertiesfmt[] = "niii";