aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormegamage <none@none>2009-05-05 16:56:15 -0500
committermegamage <none@none>2009-05-05 16:56:15 -0500
commite69d2cbed95b6cddd009f68dd80fd4614342d1fc (patch)
tree8dd0777d15adf284f2b0146e791ac4cd868b36e3
parentdcb2b5aa019c409b1b9b1061aa4dd24c8ecacb5d (diff)
[7776] Completed implementation of CMSG_SPELLCLICK Author: arrai
For vehicles, you have to add the correct SPELL_AURA_CONTROL_VEHICLE spells to npc_spellclick_spells, otherwise you won't be able to use them --HG-- branch : trunk
-rw-r--r--sql/mangos.sql2
-rw-r--r--sql/updates/3148_mangos_7776_01_world_npc_spellclick_spells.sql8
-rw-r--r--src/game/Chat.cpp1
-rw-r--r--src/game/Chat.h1
-rw-r--r--src/game/CreatureAI.h2
-rw-r--r--src/game/Group.cpp8
-rw-r--r--src/game/Level3.cpp9
-rw-r--r--src/game/MiscHandler.cpp23
-rw-r--r--src/game/MovementHandler.cpp1
-rw-r--r--src/game/Object.cpp11
-rw-r--r--src/game/ObjectMgr.cpp70
-rw-r--r--src/game/ObjectMgr.h12
-rw-r--r--src/game/Player.cpp43
-rw-r--r--src/game/Player.h4
-rw-r--r--src/game/SpellAuras.cpp32
-rw-r--r--src/game/SpellEffects.cpp13
-rw-r--r--src/game/SpellHandler.cpp27
-rw-r--r--src/game/World.cpp3
18 files changed, 228 insertions, 42 deletions
diff --git a/sql/mangos.sql b/sql/mangos.sql
index 1fca13b12cc..6cfb3a8a82f 100644
--- a/sql/mangos.sql
+++ b/sql/mangos.sql
@@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
- `required_7720_01_mangos_mangos_string` bit(1) default NULL
+ `required_7776_01_mangos_npc_spellclick_spells` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
diff --git a/sql/updates/3148_mangos_7776_01_world_npc_spellclick_spells.sql b/sql/updates/3148_mangos_7776_01_world_npc_spellclick_spells.sql
new file mode 100644
index 00000000000..c8cd342a7f7
--- /dev/null
+++ b/sql/updates/3148_mangos_7776_01_world_npc_spellclick_spells.sql
@@ -0,0 +1,8 @@
+ALTER TABLE db_version CHANGE COLUMN required_7720_01_mangos_mangos_string required_7776_01_mangos_npc_spellclick_spells bit;
+
+CREATE TABLE `npc_spellclick_spells` (
+ `npc_entry` INT UNSIGNED NOT NULL COMMENT 'reference to creature_template',
+ `spell_id` INT UNSIGNED NOT NULL COMMENT 'spell which should be casted ',
+ `quest_id` INT UNSIGNED NOT NULL COMMENT 'reference to quest_template',
+ `cast_flags` TINYINT UNSIGNED NOT NULL COMMENT 'first bit defines caster: 1=player, 0=creature; second bit defines target, same mapping as caster bit'
+) ENGINE = MYISAM DEFAULT CHARSET=utf8;
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index c2293fb8848..1bc6eb304e4 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -455,6 +455,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPageTextsCommand, "", NULL },
{ "pickpocketing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesPickpocketingCommand,"",NULL},
{ "points_of_interest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPointsOfInterestCommand, "",NULL},
+ { "npc_spellclick_spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellClickSpellsCommand, "",NULL},
{ "prospecting_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesProspectingCommand,"", NULL },
{ "quest_mail_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesQuestMailCommand, "", NULL },
{ "quest_end_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestEndScriptsCommand, "", NULL },
diff --git a/src/game/Chat.h b/src/game/Chat.h
index 6675094e942..cc7de6731a6 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -374,6 +374,7 @@ class ChatHandler
bool HandleReloadNpcVendorCommand(const char* args);
bool HandleReloadPageTextsCommand(const char* args);
bool HandleReloadPointsOfInterestCommand(const char* args);
+ bool HandleReloadSpellClickSpellsCommand(const char* args);
bool HandleReloadQuestAreaTriggersCommand(const char* args);
bool HandleReloadQuestEndScriptsCommand(const char* args);
bool HandleReloadQuestStartScriptsCommand(const char* args);
diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h
index f99d9fe33cb..e3a5a674e68 100644
--- a/src/game/CreatureAI.h
+++ b/src/game/CreatureAI.h
@@ -242,7 +242,7 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI
void OnCharmed(bool apply);
- virtual void SpellClick(Player *player) {}
+ //virtual void SpellClick(Player *player) {}
// Called at reaching home after evade
virtual void JustReachedHome() {}
diff --git a/src/game/Group.cpp b/src/game/Group.cpp
index 601440c0466..02fc72f2022 100644
--- a/src/game/Group.cpp
+++ b/src/game/Group.cpp
@@ -210,7 +210,7 @@ void Group::ConvertToRaid()
// update quest related GO states (quest activity dependent from raid membership)
for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
if(Player* player = objmgr.GetPlayer(citr->guid))
- player->UpdateForQuestsGO();
+ player->UpdateForQuestWorldObjects();
}
bool Group::AddInvite(Player *player)
@@ -304,7 +304,7 @@ bool Group::AddMember(const uint64 &guid, const char* name)
// quest related GO state dependent from raid memebership
if(isRaidGroup())
- player->UpdateForQuestsGO();
+ player->UpdateForQuestWorldObjects();
}
return true;
@@ -323,7 +323,7 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
{
// quest related GO state dependent from raid membership
if(isRaidGroup())
- player->UpdateForQuestsGO();
+ player->UpdateForQuestWorldObjects();
WorldPacket data;
@@ -404,7 +404,7 @@ void Group::Disband(bool hideDestroy)
// quest related GO state dependent from raid membership
if(isRaidGroup())
- player->UpdateForQuestsGO();
+ player->UpdateForQuestWorldObjects();
if(!player->GetSession())
continue;
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index a7024dd0775..474a79c5680 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -576,6 +576,7 @@ bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/)
HandleReloadNpcTrainerCommand("a");
HandleReloadNpcVendorCommand("a");
HandleReloadPointsOfInterestCommand("a");
+ HandleReloadSpellClickSpellsCommand("a");
return true;
}
@@ -922,6 +923,14 @@ bool ChatHandler::HandleReloadPointsOfInterestCommand(const char*)
return true;
}
+bool ChatHandler::HandleReloadSpellClickSpellsCommand(const char*)
+{
+ sLog.outString( "Re-Loading `npc_spellclick_spells` Table!" );
+ objmgr.LoadNPCSpellClickSpells();
+ SendGlobalSysMessage("DB table `npc_spellclick_spells` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadReservedNameCommand(const char*)
{
sLog.outString( "Loading ReservedNames... (`reserved_name`)" );
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index e41e3211344..a75141e2937 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -1686,29 +1686,6 @@ void WorldSession::HandleSetTaxiBenchmarkOpcode( WorldPacket & recv_data )
sLog.outDebug("Client used \"/timetest %d\" command", mode);
}
-void WorldSession::HandleSpellClick( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- uint64 guid;
- recv_data >> guid;
-
- Creature *creature = NULL;
- if(IS_VEHICLE_GUID(guid))
- {
- Vehicle *vehicle = ObjectAccessor::GetVehicle(guid);
- if(vehicle)
- {
- _player->EnterVehicle(vehicle);
- creature = vehicle;
- }
- }
- if(!creature)
- creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
- if(creature && creature->IsAIEnabled)
- creature->AI()->SpellClick(_player);
-}
-
void WorldSession::HandleInspectAchievements( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data, 1);
diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp
index 2ef75c24be7..59d0d263227 100644
--- a/src/game/MovementHandler.cpp
+++ b/src/game/MovementHandler.cpp
@@ -26,6 +26,7 @@
#include "Corpse.h"
#include "Player.h"
#include "Vehicle.h"
+#include "SpellAuras.h"
#include "MapManager.h"
#include "Transports.h"
#include "BattleGround.h"
diff --git a/src/game/Object.cpp b/src/game/Object.cpp
index 56d52f5e49f..7adc7d306bb 100644
--- a/src/game/Object.cpp
+++ b/src/game/Object.cpp
@@ -526,9 +526,16 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
{
if( updateMask->GetBit( index ) )
{
- // remove custom flag before send
if( index == UNIT_NPC_FLAGS )
- *data << uint32(m_uint32Values[ index ] & ~(UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP));
+ {
+ // remove custom flag before sending
+ uint32 appendValue = m_uint32Values[ index ] & ~(UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP);
+
+ if (GetTypeId() == TYPEID_UNIT && !target->canSeeSpellClickOn((Creature*)this))
+ appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
+
+ *data << uint32(appendValue);
+ }
// FIXME: Some values at server stored in float format but must be sent to client in uint32 format
else if(index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
{
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index a2af970e9f3..12fb26f0ad8 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -6207,6 +6207,76 @@ void ObjectMgr::LoadPointsOfInterest()
sLog.outString(">> Loaded %u Points of Interest definitions", count);
}
+void ObjectMgr::LoadNPCSpellClickSpells()
+{
+ uint32 count = 0;
+
+ mSpellClickInfoMap.clear();
+
+ QueryResult *result = WorldDatabase.Query("SELECT npc_entry, spell_id, quest_id, cast_flags FROM npc_spellclick_spells");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 spellclick spells. DB table `npc_spellclick_spells` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 npc_entry = fields[0].GetUInt32();
+ CreatureInfo const* cInfo = GetCreatureTemplate(npc_entry);
+ if (!cInfo)
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown creature_template %u. Skipping entry.", npc_entry);
+ continue;
+ }
+
+ uint32 spellid = fields[1].GetUInt32();
+ SpellEntry const *spellinfo = sSpellStore.LookupEntry(spellid);
+ if (!spellinfo)
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown spellid %u. Skipping entry.", spellid);
+ continue;
+ }
+
+ uint32 quest = fields[2].GetUInt32();
+
+ // quest might be 0 to enable spellclick independent of any quest
+ if (quest)
+ {
+ if(mQuestTemplates.find(quest) == mQuestTemplates.end())
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown quest %u. Skipping entry.", spellid);
+ continue;
+ }
+
+ }
+
+ uint8 castFlags = fields[3].GetUInt8();
+ SpellClickInfo info;
+ info.spellId = spellid;
+ info.questId = quest;
+ info.castFlags = castFlags;
+ mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info));
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u spellclick definitions", count);
+}
+
void ObjectMgr::LoadWeatherZoneChances()
{
uint32 count = 0;
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index e655d122e41..eff1f3812a1 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -99,6 +99,15 @@ extern ScriptMapMap sGameObjectScripts;
extern ScriptMapMap sEventScripts;
extern ScriptMapMap sWaypointScripts;
+struct SpellClickInfo
+{
+ uint32 spellId;
+ uint32 questId;
+ uint8 castFlags;
+};
+
+typedef std::multimap<uint32, SpellClickInfo> SpellClickInfoMap;
+
struct AreaTrigger
{
uint32 access_id;
@@ -569,6 +578,9 @@ class ObjectMgr
void LoadReputationOnKill();
void LoadPointsOfInterest();
+ SpellClickInfoMap mSpellClickInfoMap;
+ void LoadNPCSpellClickSpells();
+
void LoadWeatherZoneChances();
void LoadGameTele();
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index c03fe059851..0f1cce9bab3 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -12562,7 +12562,7 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
CastSpell(this,itr->second->spellId,true);
}
- UpdateForQuestsGO();
+ UpdateForQuestWorldObjects();
}
void Player::CompleteQuest( uint32 quest_id )
@@ -13293,7 +13293,7 @@ void Player::SetQuestStatus( uint32 quest_id, QuestStatus status )
if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
}
- UpdateForQuestsGO();
+ UpdateForQuestWorldObjects();
}
// not used in TrinIty, but used in scripting code
@@ -13414,7 +13414,7 @@ void Player::ItemAddedQuestCheck( uint32 entry, uint32 count )
}
}
}
- UpdateForQuestsGO();
+ UpdateForQuestWorldObjects();
}
void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count )
@@ -13455,7 +13455,7 @@ void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count )
}
}
}
- UpdateForQuestsGO();
+ UpdateForQuestWorldObjects();
}
void Player::KilledMonster( uint32 entry, uint64 guid )
@@ -18890,7 +18890,7 @@ bool Player::HasQuestForGO(int32 GOId) const
return false;
}
-void Player::UpdateForQuestsGO()
+void Player::UpdateForQuestWorldObjects()
{
if(m_clientGUIDs.empty())
return;
@@ -18905,6 +18905,24 @@ void Player::UpdateForQuestsGO()
if(obj)
obj->BuildValuesUpdateBlockForPlayer(&udata,this);
}
+ else if(IS_CREATURE_GUID(*itr) || IS_VEHICLE_GUID(*itr))
+ {
+ Creature *obj = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, *itr);
+ if(!obj)
+ continue;
+ // check if this unit requires quest specific flags
+
+ SpellClickInfoMap const& map = objmgr.mSpellClickInfoMap;
+ for(SpellClickInfoMap::const_iterator itr = map.lower_bound(obj->GetEntry()); itr != map.upper_bound(obj->GetEntry()); ++itr)
+ {
+ if(itr->second.questId != 0)
+ {
+ obj->BuildCreateUpdateBlockForPlayer(&udata,this);
+ break;
+ }
+ }
+
+ }
}
udata.BuildPacket(&packet);
GetSession()->SendPacket(&packet);
@@ -20455,3 +20473,18 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
m_temporaryUnsummonedPetNumber = 0;
}
+
+bool Player::canSeeSpellClickOn(Creature const *c) const
+{
+ SpellClickInfoMap const& map = objmgr.mSpellClickInfoMap;
+ if(map.empty())
+ return true;
+
+ for(SpellClickInfoMap::const_iterator itr = map.lower_bound(c->GetEntry()); itr != map.upper_bound(c->GetEntry()); ++itr)
+ {
+ if(itr->second.questId == 0 || GetQuestStatus(itr->second.questId) == QUEST_STATUS_INCOMPLETE)
+ return true;
+ }
+ return false;
+}
+
diff --git a/src/game/Player.h b/src/game/Player.h
index 0f1c7b6689f..ecab25122bf 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -1160,7 +1160,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void ReputationChanged(FactionEntry const* factionEntry );
bool HasQuestForItem( uint32 itemid ) const;
bool HasQuestForGO(int32 GOId) const;
- void UpdateForQuestsGO();
+ void UpdateForQuestWorldObjects();
bool CanShareQuest(uint32 quest_id) const;
void SendQuestComplete( uint32 quest_id );
@@ -2028,6 +2028,8 @@ class TRINITY_DLL_SPEC Player : public Unit
bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); }
void SetTitle(CharTitlesEntry const* title);
+ //bool isActiveObject() const { return true; }
+ bool canSeeSpellClickOn(Creature const* creature) const;
protected:
/*********************************************************/
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 264a4c39aea..29783de6c70 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -47,6 +47,7 @@
#include "Util.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
+#include "Vehicle.h"
#include "CellImpl.h"
pAuraHandler AuraHandler[TOTAL_AURAS]=
@@ -6726,19 +6727,40 @@ void AuraEffect::HandleArenaPreparation(bool apply, bool Real)
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION);
}
+/**
+ * Such auras are applied from a caster(=player) to a vehicle.
+ * This has been verified using spell #49256
+ */
void AuraEffect::HandleAuraControlVehicle(bool apply, bool Real)
{
if(!Real)
return;
- if(m_target->GetTypeId() != TYPEID_PLAYER)
+ if(m_target->GetTypeId() != TYPEID_UNIT || !((Creature*)m_target)->isVehicle())
+ return;
+
+ Unit *caster = GetCaster();
+ if(!caster)
return;
- if(Pet *pet = ((Player*)m_target)->GetPet())
- pet->Remove(PET_SAVE_AS_CURRENT);
+ Vehicle *vehicle = dynamic_cast<Vehicle*>(m_target);
- //WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
- //((Player*)m_target)->GetSession()->SendPacket(&data);
+ if (apply)
+ {
+ if(caster->GetTypeId() == TYPEID_PLAYER)
+ if(Pet *pet = ((Player*)caster)->GetPet())
+ pet->Remove(PET_SAVE_AS_CURRENT);
+ caster->EnterVehicle(vehicle);
+ }
+ else
+ {
+ SpellEntry const *spell = GetSpellProto();
+
+ // some SPELL_AURA_CONTROL_VEHICLE auras have a dummy effect on the player - remove them
+ caster->RemoveAurasDueToSpell(spell->Id);
+
+ caster->ExitVehicle();
+ }
}
void AuraEffect::HandleAuraConvertRune(bool apply, bool Real)
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index f08299631cd..3915d61d876 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -1227,6 +1227,19 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastSpell(m_caster, 30452, true, NULL);
return;
}
+ case 51592: // Pickup Primordial Hatchling
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
+ return;
+
+ Creature* creatureTarget = (Creature*)unitTarget;
+
+ creatureTarget->setDeathState(JUST_DIED);
+ creatureTarget->RemoveCorpse();
+ creatureTarget->SetHealth(0); // just for nice GM-mode view
+ return;
+
+ }
case 52308:
{
switch(i)
diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp
index 5cd5da67118..c24a9e2bb92 100644
--- a/src/game/SpellHandler.cpp
+++ b/src/game/SpellHandler.cpp
@@ -483,3 +483,30 @@ void WorldSession::HandleSelfResOpcode( WorldPacket & /*recv_data*/ )
}
}
+void WorldSession::HandleSpellClick( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ uint64 guid;
+ recv_data >> guid;
+
+ Creature *unit = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
+
+ if(!unit)
+ return;
+
+ SpellClickInfoMap const& map = objmgr.mSpellClickInfoMap;
+ for(SpellClickInfoMap::const_iterator itr = map.lower_bound(unit->GetEntry()); itr != map.upper_bound(unit->GetEntry()); ++itr)
+ {
+ if(itr->second.questId == 0 || _player->GetQuestStatus(itr->second.questId) == QUEST_STATUS_INCOMPLETE)
+ {
+ Unit *caster = (itr->second.castFlags & 0x1) ? (Unit*)_player : (Unit*)unit;
+ Unit *target = (itr->second.castFlags & 0x2) ? (Unit*)_player : (Unit*)unit;
+
+ caster->CastSpell(target, itr->second.spellId, true);
+ }
+ }
+
+ if(unit->isVehicle())
+ _player->EnterVehicle((Vehicle*)unit);
+}
diff --git a/src/game/World.cpp b/src/game/World.cpp
index 9615a378faa..fa44e527da5 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -1293,6 +1293,9 @@ void World::SetInitialWorldSettings()
sLog.outString( ">>> Quests Relations loaded" );
sLog.outString();
+ sLog.outString( "Loading UNIT_NPC_FLAG_SPELLCLICK Data..." );
+ objmgr.LoadNPCSpellClickSpells();
+
sLog.outString( "Loading SpellArea Data..." ); // must be after quest load
spellmgr.LoadSpellAreas();