diff options
| author | QAston <none@none> | 2010-07-24 22:41:42 +0200 |
|---|---|---|
| committer | QAston <none@none> | 2010-07-24 22:41:42 +0200 |
| commit | 2352fc7cdfff0e677f6516c0ab2b91d3efc9ab70 (patch) | |
| tree | 470b0d66f513cb62b6be88863003408864d117ae /src/server/game | |
| parent | 687cd83bddfbc5416ba11bff53c8a636747a5802 (diff) | |
*Add base scripting interfce for spells - thanks to Brian for help in making it compile with GCC.
*Add hook for handling spell effects in new scripting system.
--HG--
branch : trunk
Diffstat (limited to 'src/server/game')
| -rw-r--r-- | src/server/game/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 109 | ||||
| -rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 8 | ||||
| -rw-r--r-- | src/server/game/Miscellaneous/SharedDefines.h | 16 | ||||
| -rw-r--r-- | src/server/game/PrecompiledHeaders/ScriptPCH.h | 1 | ||||
| -rw-r--r-- | src/server/game/Scripting/ScriptLoader.cpp | 27 | ||||
| -rw-r--r-- | src/server/game/Scripting/ScriptMgr.cpp | 22 | ||||
| -rw-r--r-- | src/server/game/Scripting/ScriptMgr.h | 9 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 40 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.h | 8 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellScript.cpp | 215 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellScript.h | 154 | ||||
| -rw-r--r-- | src/server/game/World/World.cpp | 6 |
13 files changed, 612 insertions, 4 deletions
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 40fc77ff464..5738d7b8fc7 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -172,6 +172,7 @@ set(game_STAT_SRCS Spells/SpellEffects.cpp Spells/Spell.cpp Spells/SpellMgr.cpp + Spells/SpellScript.cpp Tools/CharacterDatabaseCleaner.cpp Tools/PlayerDump.cpp Tools/Tools.cpp diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 87f8202ddcc..31e6c0c0c72 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -46,6 +46,8 @@ #include "Vehicle.h" #include "AchievementMgr.h" #include "DisableMgr.h" +#include "ScriptMgr.h" +#include "SpellScript.h" ScriptMapMap sQuestEndScripts; ScriptMapMap sQuestStartScripts; @@ -4893,6 +4895,106 @@ void ObjectMgr::LoadWaypointScripts() } } +void ObjectMgr::LoadSpellScriptNames() +{ + mSpellScripts.clear(); // need for reload case + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT spell_id, ScriptName FROM spell_script_names"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u spell script names", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + int32 spellId = fields[0].GetInt32(); + const char *scriptName = fields[1].GetString(); + + bool allRanks = false; + if (spellId <=0) + { + allRanks = true; + spellId = -spellId; + } + + SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId); + if (!spellEntry) + { + sLog.outErrorDb("Scriptname:`%s` spell (spell_id:%d) does not exist in `Spell.dbc`.",scriptName,fields[0].GetInt32()); + continue; + } + + if (allRanks) + { + if (spellmgr.GetFirstSpellInChain(spellId) != spellId) + { + sLog.outErrorDb("Scriptname:`%s` spell (spell_id:%d) is not first rank of spell.",scriptName,fields[0].GetInt32()); + continue; + } + while(spellId) + { + mSpellScripts.insert(SpellScriptsMap::value_type(spellId, GetScriptId(scriptName))); + spellId = spellmgr.GetNextSpellInChain(spellId); + } + } + else + mSpellScripts.insert(SpellScriptsMap::value_type(spellId, GetScriptId(scriptName))); + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u spell script names", count); +} + +void ObjectMgr::ValidateSpellScripts() +{ + if (mSpellScripts.empty()) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Validation done"); + return; + } + + barGoLink bar(mSpellScripts.size()); + for (SpellScriptsMap::iterator itr = mSpellScripts.begin(); itr != mSpellScripts.end();) + { + SpellEntry const * spellEntry = sSpellStore.LookupEntry(itr->first); + std::vector<std::pair<SpellScript *, SpellScriptsMap::iterator> > spellScripts; + sScriptMgr.CreateSpellScripts(itr->first, spellScripts); + SpellScriptsMap::iterator bitr; + itr = mSpellScripts.upper_bound(itr->first); + + for (std::vector<std::pair<SpellScript *, SpellScriptsMap::iterator> >::iterator sitr = spellScripts.begin(); sitr != spellScripts.end(); ++sitr) + { + bar.step(); + sitr->first->Register(); + if (!sitr->first->_Validate(spellEntry, objmgr.GetScriptName(sitr->second->second))) + mSpellScripts.erase(sitr->second); + delete sitr->first; + } + } + + sLog.outString(); + sLog.outString(">> Validation done"); +} + void ObjectMgr::LoadGossipScripts() { LoadScripts(sGossipScripts, "gossip_scripts"); @@ -7658,6 +7760,11 @@ uint32 ObjectMgr::GetAreaTriggerScriptId(uint32 trigger_id) return 0; } +SpellScriptsBounds ObjectMgr::GetSpellScriptsBounds(uint32 spell_id) +{ + return SpellScriptsBounds(mSpellScripts.lower_bound(spell_id),mSpellScripts.upper_bound(spell_id)); +} + SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial) { switch(pSkill->categoryId) @@ -8451,6 +8558,8 @@ void ObjectMgr::LoadScriptNames() "UNION " "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' " "UNION " + "SELECT DISTINCT(ScriptName) FROM spell_script_names WHERE ScriptName <> '' " + "UNION " "SELECT DISTINCT(script) FROM instance_template WHERE script <> ''"); if (!result) diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index e02fe438c5c..c99a58fe7fb 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -90,6 +90,8 @@ struct ScriptInfo typedef std::multimap<uint32, ScriptInfo> ScriptMap; typedef std::map<uint32, ScriptMap > ScriptMapMap; +typedef std::multimap<uint32, uint32> SpellScriptsMap; +typedef std::pair<SpellScriptsMap::iterator, SpellScriptsMap::iterator> SpellScriptsBounds; extern ScriptMapMap sQuestEndScripts; extern ScriptMapMap sQuestStartScripts; extern ScriptMapMap sSpellScripts; @@ -521,6 +523,7 @@ class ObjectMgr AreaTrigger const* GetMapEntranceTrigger(uint32 Map) const; uint32 GetAreaTriggerScriptId(uint32 trigger_id); + SpellScriptsBounds GetSpellScriptsBounds(uint32 spell_id); ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const { @@ -587,6 +590,9 @@ class ObjectMgr void LoadGossipScripts(); void LoadWaypointScripts(); + void LoadSpellScriptNames(); + void ValidateSpellScripts(); + bool LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); bool LoadTrinityStrings() { return LoadTrinityStrings(WorldDatabase,"trinity_string",MIN_TRINITY_STRING_ID,MAX_TRINITY_STRING_ID); } void LoadDbScriptStrings(); @@ -1002,6 +1008,8 @@ class ObjectMgr SpellClickInfoMap mSpellClickInfoMap; + SpellScriptsMap mSpellScripts; + ItemRequiredTargetMap m_ItemRequiredTarget; VehicleAccessoryMap m_VehicleAccessoryMap; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 115e5337e5b..54dfd749b66 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -24,6 +24,17 @@ #include "Define.h" #include <cassert> +enum SpellEffIndex +{ + EFFECT_0 = 0, + EFFECT_1 = 1, + EFFECT_2 = 2, +}; + +// used in script definitions +#define EFFECT_FIRST_FOUND 254 +#define EFFECT_ALL 255 + // loot modes for creatures and gameobjects, bitmask! enum LootModes { @@ -1177,7 +1188,7 @@ enum Targets TARGET_UNIT_MINIPET = 90, TARGET_DEST_DEST_RANDOM_DIR_DIST = 91, TARGET_UNIT_UNK_92 = 92, - TARGET_CORPSE_AREA_ENEMY_PLAYER_SRC= 93, + TARGET_CORPSE_AREA_ENEMY_PLAYER_SRC= 93, // TODO TARGET_UNIT_VEHICLE = 94, TARGET_UNIT_DRIVER = 95, TARGET_UNIT_PASSENGER_0 = 96, @@ -1190,6 +1201,9 @@ enum Targets TARGET_UNIT_PASSENGER_7 = 103, TARGET_UNIT_AREA_PATH = 104, TARGET_UNIT_UNK_105 = 105, // 1 spell + TARGET_DEST_CHANNEL_TARGET = 106, // TODO + TARGET_UNK_AREA_UNK_DST_107 = 107, // not enough info - only generic spells avalible + TARGET_GAMEOBJECT_AREA_PATH = 108, // TODO TARGET_DEST_UNK_110 = 110, // some kind of traj? }; diff --git a/src/server/game/PrecompiledHeaders/ScriptPCH.h b/src/server/game/PrecompiledHeaders/ScriptPCH.h index f8515e99f89..b716edc3a5b 100644 --- a/src/server/game/PrecompiledHeaders/ScriptPCH.h +++ b/src/server/game/PrecompiledHeaders/ScriptPCH.h @@ -22,6 +22,7 @@ #include "DBCStructure.h" #include "DBCStores.h" #include "ObjectMgr.h" +#include "SpellScript.h" #ifdef _WIN32 #include <windows.h> diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index cf378db2bac..54bd9150a91 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -513,6 +513,20 @@ void AddSC_terokkar_forest(); void AddSC_zangarmarsh(); void AddSC_onevents(); +// spells +void AddSC_deathknight_spell_scripts(); +void AddSC_druid_spell_scripts(); +void AddSC_generic_spell_scripts(); +void AddSC_hunter_spell_scripts(); +void AddSC_mage_spell_scripts(); +void AddSC_paladin_spell_scripts(); +void AddSC_priest_spell_scripts(); +void AddSC_rogue_spell_scripts(); +void AddSC_shaman_spell_scripts(); +void AddSC_warlock_spell_scripts(); +void AddSC_warrior_spell_scripts(); +void AddSC_example_spell_scripts(); + #endif void AddScripts() @@ -1015,5 +1029,18 @@ void AddScripts() AddSC_zangarmarsh(); AddSC_onevents(); + // spells + AddSC_deathknight_spell_scripts(); + AddSC_druid_spell_scripts(); + AddSC_generic_spell_scripts(); + AddSC_hunter_spell_scripts(); + AddSC_mage_spell_scripts(); + AddSC_paladin_spell_scripts(); + AddSC_priest_spell_scripts(); + AddSC_rogue_spell_scripts(); + AddSC_shaman_spell_scripts(); + AddSC_warlock_spell_scripts(); + AddSC_warrior_spell_scripts(); + AddSC_example_spell_scripts(); #endif } diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 70b1ff6be64..5f6cce4917d 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -544,3 +544,25 @@ InstanceData* ScriptMgr::CreateInstanceData(Map *map) return tmpscript->GetInstanceData(map); } +void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::list<SpellScript *> & script_vector) +{ + SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); + for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) + { + Script *tmpscript = m_scripts[itr->second]; + if (!tmpscript || !tmpscript->GetSpellScript) continue; + script_vector.push_back(tmpscript->GetSpellScript()); + } +} + +void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::vector<std::pair<SpellScript *, SpellScriptsMap::iterator> > & script_vector) +{ + SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); + script_vector.reserve(std::distance(bounds.first, bounds.second)); + for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) + { + Script *tmpscript = m_scripts[itr->second]; + if (!tmpscript || !tmpscript->GetSpellScript) continue; + script_vector.push_back(std::make_pair(tmpscript->GetSpellScript(), itr)); + } +} diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index bcb26381809..d477d7a1e39 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -17,6 +17,7 @@ class Player; class Creature; class CreatureAI; class InstanceData; +class SpellScript; class Quest; class Item; class GameObject; @@ -25,6 +26,7 @@ class Map; class Unit; class WorldObject; struct ItemPrototype; +class Spell; #define MAX_SCRIPTS 5000 //72 bytes each (approx 351kb) #define VISIBLE_RANGE (166.0f) //MAX visible range (size of grid) @@ -42,7 +44,7 @@ struct Script pChooseReward(NULL), pGODestroyed(NULL), pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pItemQuestAccept(NULL), pGOQuestAccept(NULL), pGOChooseReward(NULL),pItemUse(NULL), pItemExpire(NULL), pEffectDummyCreature(NULL), pEffectDummyGameObj(NULL), pEffectDummyItem(NULL), - GetAI(NULL), GetInstanceData(NULL) + GetAI(NULL), GetInstanceData(NULL), GetSpellScript(NULL) {} std::string Name; @@ -89,6 +91,9 @@ struct Script CreatureAI* (*GetAI)(Creature*); InstanceData* (*GetInstanceData)(Map*); + SpellScript*(*GetSpellScript)(); + //AuraScript*(*GetAuraScript)(); + void RegisterSelf(); }; @@ -143,6 +148,8 @@ class ScriptMgr bool EffectDummyGameObj(Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget); bool EffectDummyItem(Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget); InstanceData* CreateInstanceData(Map *map); + void CreateSpellScripts(uint32 spell_id, std::list<SpellScript *> & script_vector); + void CreateSpellScripts(uint32 spell_id, std::vector<std::pair<SpellScript *, SpellScriptsMap::iterator> > & script_vector); }; //Config file accessors diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index a53142bf296..eb7c2c9b4fa 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -52,6 +52,7 @@ #include "ScriptMgr.h" #include "ConditionMgr.h" #include "DisableMgr.h" +#include "SpellScript.h" #define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS) @@ -455,6 +456,14 @@ Spell::Spell(Unit* Caster, SpellEntry const *info, bool triggered, uint64 origin Spell::~Spell() { + // unload scripts + while(!m_loadedScripts.empty()) + { + std::list<SpellScript *>::iterator itr = m_loadedScripts.begin(); + (*itr)->Unload(); + delete (*itr); + m_loadedScripts.erase(itr); + } if (m_referencedFromCurrentSpell && m_selfContainer && *m_selfContainer == this) { // Clean the reference to avoid later crash. @@ -2748,6 +2757,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const * triggere finish(false); return; } + LoadScripts(); if (m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->ToPlayer()->SetSpellModTakingSpell(this, true); @@ -4479,7 +4489,6 @@ void Spell::HandleThreatSpells(uint32 spellId) void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i) { - if (!sScriptMgr.OnSpellCast(pUnitTarget,pItemTarget,pGOTarget,i,m_spellInfo)) return; @@ -4495,12 +4504,21 @@ void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTar sLog.outDebug("Spell: %u Effect : %u", m_spellInfo->Id, eff); + for(std::list<SpellScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + std::list<SpellScript::EffectHandler>::iterator effEndItr = (*scritr)->EffectHandlers.end(), effItr = (*scritr)->EffectHandlers.begin(); + for(; effItr != effEndItr ; ++effItr) + { + if ((*effItr).IsEffectAffected(m_spellInfo, i)) + (*effItr).Call(*scritr, (SpellEffIndex)i); + } + } + //we do not need DamageMultiplier here. damage = CalculateDamage(i, NULL); if (eff < TOTAL_SPELL_EFFECTS) { - //sLog.outDebug("WORLD: Spell FX %d < TOTAL_SPELL_EFFECTS ", eff); (this->*SpellEffects[eff])(i); } } @@ -7076,3 +7094,21 @@ void Spell::SelectTrajTargets() m_targets.setDst(x, y, z, m_caster->GetOrientation()); } } + +void Spell::LoadScripts() +{ + sLog.outError("Spell::LoadScripts"); + sScriptMgr.CreateSpellScripts(m_spellInfo->Id, m_loadedScripts); + for(std::list<SpellScript *>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end() ;) + { + if (!(*itr)->_Load(this)) + { + std::list<SpellScript *>::iterator bitr = itr; + ++itr; + m_loadedScripts.erase(bitr); + continue; + } + (*itr)->Register(); + ++itr; + } +} diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 563572ec1fd..368add34926 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -29,6 +29,8 @@ class Player; class GameObject; class DynamicObject; class Aura; +struct SpellEntry; +class SpellScript; // These flags represent the inner states of the targeting system enum SpellInternalTargetFlags @@ -268,6 +270,7 @@ class Spell { friend struct Trinity::SpellNotifierCreatureAndPlayer; friend void Unit::SetCurrentCastedSpell(Spell * pSpell); + friend class SpellScript; public: void EffectNULL(uint32); @@ -506,6 +509,7 @@ class Spell Unit* GetCaster() const { return m_caster; } Unit* GetOriginalCaster() const { return m_originalCaster; } + SpellEntry const * GetSpellInfo() const { return m_spellInfo; } int32 GetPowerCost() const { return m_powerCost; } void UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc) @@ -650,6 +654,10 @@ class Spell void SpellDamageWeaponDmg(uint32 i); void SpellDamageHeal(uint32 i); + // Scripting system + void LoadScripts(); + std::list<SpellScript *> m_loadedScripts; + // effect helpers void GetSummonPosition(uint32 i, Position &pos, float radius = 0.0f, uint32 count = 0); void SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const *properties); diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp new file mode 100644 index 00000000000..fb2944fa651 --- /dev/null +++ b/src/server/game/Spells/SpellScript.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "SpellScript.h" +#include "Spell.h" + +bool _SpellScript::_Validate(SpellEntry const * entry, const char * scriptname) +{ + if (!Validate(entry)) + { + sLog.outError("TSCR: Spell `%u` did not pass Validate() function of script `%s` - script will be not added to the spell", entry->Id, scriptname); + return false; + } + return true; +} + +_SpellScript::EffectHook::EffectHook(uint8 _effIndex) +{ + // effect index must be in range <0;2>, allow use of special effindexes + ASSERT(_effIndex == EFFECT_ALL || _effIndex == EFFECT_FIRST_FOUND || _effIndex < MAX_SPELL_EFFECTS); + effIndex = _effIndex; +} + +uint8 _SpellScript::EffectHook::GetAffectedEffectsMask(SpellEntry const * spellEntry) +{ + uint8 mask = 0; + if ((effIndex == EFFECT_ALL) || (effIndex == EFFECT_FIRST_FOUND)) + { + for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if ((effIndex == EFFECT_FIRST_FOUND) && mask) + return mask; + if (CheckEffect(spellEntry, effIndex)) + mask |= (uint8)1<<effIndex; + } + } + else + { + if (CheckEffect(spellEntry, effIndex)) + mask |= (uint8)1<<effIndex; + } + return mask; +} + +bool _SpellScript::EffectHook::IsEffectAffected(SpellEntry const * spellEntry, uint8 effIndex) +{ + return GetAffectedEffectsMask(spellEntry) & 1<<effIndex; +} + +std::string _SpellScript::EffectHook::EffIndexToString() +{ + switch(effIndex) + { + case EFFECT_ALL: + return "EFFECT_ALL"; + case EFFECT_FIRST_FOUND: + return "EFFECT_FIRST_FOUND"; + case EFFECT_0: + return "EFFECT_0"; + case EFFECT_1: + return "EFFECT_1"; + case EFFECT_2: + return "EFFECT_2"; + } + return "Invalid Value"; +} + +bool _SpellScript::EffectNameCheck::Check(SpellEntry const * spellEntry, uint8 effIndex) +{ + if (!spellEntry->Effect[effIndex] && !effName) + return true; + if (!spellEntry->Effect[effIndex]) + return false; + return (effName == SPELL_EFFECT_ANY) || (spellEntry->Effect[effIndex] == effName); +} + +std::string _SpellScript::EffectNameCheck::ToString() +{ + switch(effName) + { + case SPELL_EFFECT_ANY: + return "SPELL_EFFECT_ANY"; + default: + char num[10]; + sprintf (num,"%u",effName); + return num; + } +} + +bool _SpellScript::EffectAuraNameCheck::Check(SpellEntry const * spellEntry, uint8 effIndex) +{ + if (!spellEntry->EffectApplyAuraName[effIndex] && !effAurName) + return true; + if (!spellEntry->EffectApplyAuraName[effIndex]) + return false; + return (effAurName == SPELL_EFFECT_ANY) || (spellEntry->EffectApplyAuraName[effIndex] == effAurName); +} + +std::string _SpellScript::EffectAuraNameCheck::ToString() +{ + switch(effAurName) + { + case SPELL_AURA_ANY: + return "SPELL_AURA_ANY"; + default: + char num[10]; + sprintf (num,"%u",effAurName); + return num; + } +} + +SpellScript::EffectHandler::EffectHandler(EffectHandlerFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName) + : _SpellScript::EffectNameCheck(_effName), _SpellScript::EffectHook(_effIndex) +{ + pEffectHandlerScript = _pEffectHandlerScript; +} + +std::string SpellScript::EffectHandler::ToString() +{ + return "Index: " + EffIndexToString() + " Name: " +_SpellScript::EffectNameCheck::ToString(); +} + +bool SpellScript::EffectHandler::CheckEffect(SpellEntry const * spellEntry, uint8 effIndex) +{ + return _SpellScript::EffectNameCheck::Check(spellEntry, effIndex); +} + +void SpellScript::EffectHandler::Call(SpellScript * spellScript, SpellEffIndex effIndex) +{ + (spellScript->*pEffectHandlerScript)(effIndex); +} + +bool SpellScript::_Validate(SpellEntry const * entry, const char * scriptname) +{ + for (std::list<EffectHandler>::iterator itr = EffectHandlers.begin(); itr != EffectHandlers.end(); ++itr) + { + if (!(*itr).GetAffectedEffectsMask(entry)) + { + sLog.outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), scriptname); + } + } + return _SpellScript::_Validate(entry, scriptname); +} + +bool SpellScript::_Load(Spell * spell) +{ + m_spell = spell; + return Load(); +} + +Unit * SpellScript::GetCaster() +{ + return m_spell->GetCaster(); +} + +Unit * SpellScript::GetOriginalCaster() +{ + return m_spell->GetOriginalCaster(); +} + +SpellEntry const * SpellScript::GetSpellInfo() +{ + return m_spell->GetSpellInfo(); +} + +Unit * SpellScript::GetEffectUnitTarget() +{ + return m_spell->unitTarget; +} + +Creature * SpellScript::GetEffectCreatureTarget() +{ + if (m_spell->unitTarget) + return m_spell->unitTarget->ToCreature(); + else + return NULL; +} + +Player * SpellScript::GetEffectPlayerTarget() +{ + if (m_spell->unitTarget) + return m_spell->unitTarget->ToPlayer(); + else + return NULL; +} + +Item * SpellScript::GetEffectItemTarget() +{ + return m_spell->itemTarget; +} + +GameObject * SpellScript::GetEffectGOTarget() +{ + return m_spell->gameObjTarget; +} + +int32 SpellScript::GetEffectValue() +{ + return m_spell->damage; +} diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h new file mode 100644 index 00000000000..73b378db20e --- /dev/null +++ b/src/server/game/Spells/SpellScript.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SPELL_SCRIPT_H +#define __SPELL_SCRIPT_H + +class Unit; +struct SpellEntry; +class SpellScript; +class Spell; + +typedef void(SpellScript::*EffectHandlerFnType)(SpellEffIndex); + +#define SPELL_EFFECT_ANY (uint16)-1 +#define SPELL_AURA_ANY (uint16)-1 + +// helper class from which SpellScript and SpellAura derive, use these classes instead +class _SpellScript +{ + // internal use classes & functions + // DO NOT OVERRIDE THESE IN SCRIPTS + protected: + virtual bool _Validate(SpellEntry const * entry, const char * scriptname); + protected: + class EffectHook + { + public: + EffectHook(uint8 _effIndex); + uint8 GetAffectedEffectsMask(SpellEntry const * spellEntry); + bool IsEffectAffected(SpellEntry const * spellEntry, uint8 effIndex); + virtual bool CheckEffect(SpellEntry const * spellEntry, uint8 effIndex) = 0; + std::string EffIndexToString(); + protected: + uint8 effIndex; + }; + class EffectNameCheck + { + public: + EffectNameCheck(uint16 _effName) {effName = _effName;}; + bool Check(SpellEntry const * spellEntry, uint8 effIndex); + std::string ToString(); + private: + uint16 effName; + }; + class EffectAuraNameCheck + { + public: + EffectAuraNameCheck(uint16 _effAurName) { effAurName = _effAurName; } + bool Check(SpellEntry const * spellEntry, uint8 effIndex); + std::string ToString(); + private: + uint16 effAurName; + }; + public: + // + // SpellScript/AuraScript interface base + // these functions are safe to override, see notes below for usage instructions + // + // Function in which handler functions are registered, must be implemented in script + virtual void Register() = 0; + // Function called on server startup, if returns false script won't be used in core + // use for: dbc/template data presence/correctness checks + virtual bool Validate(SpellEntry const * spellEntry) {return true;}; + // Function called when script is created, if returns false script will be unloaded afterwards + // use for: initializing local script variables (DO NOT USE CONSTRUCTOR FOR THIS PURPOSE!) + virtual bool Load() {return true;}; + // Function called when script is destroyed + // use for: deallocating memory allocated by script + virtual void Unload() {}; +}; + +class SpellScript : public _SpellScript +{ + // internal use classes & functions + // DO NOT OVERRIDE THESE IN SCRIPTS + public: + class EffectHandler : public _SpellScript::EffectNameCheck, public _SpellScript::EffectHook + { + public: + EffectHandler(EffectHandlerFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName); + std::string ToString(); + bool CheckEffect(SpellEntry const * spellEntry, uint8 effIndex); + void Call(SpellScript * spellScript, SpellEffIndex effIndex); + private: + EffectHandlerFnType pEffectHandlerScript; + }; + public: + bool _Validate(SpellEntry const * entry, const char * scriptname); + bool _Load(Spell * spell); + private: + Spell * m_spell; + public: + // + // SpellScript interface + // hooks to which you can attach your functions + // + // List of functions registered by EffectHandlerFn + // allows more than one hook + // example EffectHandlers += EffectHandlerFn(class::function, EffectIndexSpecifier, EffectNameSpecifier); + HookList<EffectHandler> EffectHandlers; + + // methods allowing interaction with Spell object + Unit * GetCaster(); + Unit * GetOriginalCaster(); + SpellEntry const * GetSpellInfo(); + // functions useable only during spell hit on target phase + Unit * GetEffectUnitTarget(); + Creature * GetEffectCreatureTarget(); + Player * GetEffectPlayerTarget(); + Item * GetEffectItemTarget(); + GameObject * GetEffectGOTarget(); + int32 GetEffectValue(); +}; +// SpellScript interface +// +// function registering macros, should be used only in Register() +// +// EffectHandlerFn +// called at: Spell hit on unit, just before default effect handler, called for effects matching EffectIndexSpecifier and EffectNameSpecifier conditions +// hook parameter is current effect index +// parameters: function to call, EffectIndexSpecifier, EffectNameSpecifier +#define EffectHandlerFn(F, I, N) EffectHandler((EffectHandlerFnType)&F, I, N) + +// +// definitions: +// +// EffectIndexSpecifier - specifies conditions for effects +// EFFECT_0 - first effect matches +// EFFECT_1 - second effect matches +// EFFECT_2 - third effect matches +// EFFECT_FIRST_FOUND - first effect matching other conditions matches +// EFFECT_ALL - all effects of spell match +// +// EffectNameSpecifier - specifies conditions for spell effect names +// SPELL_EFFECT_ANY - any effect but not 0 matches condition +// SPELL_EFFECT_XXX - one of values of enum SpellEffects - effect with equal name matches +// + +#endif // __SPELL_SCRIPT_H diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 5eba5f44182..610a34ee5fe 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1616,9 +1616,15 @@ void World::SetInitialWorldSettings() sLog.outString("Loading CreatureEventAI Scripts..."); CreatureEAI_Mgr.LoadCreatureEventAI_Scripts(); + sLog.outString("Loading spell script names..."); + objmgr.LoadSpellScriptNames(); + sLog.outString("Initializing Scripts..."); sScriptMgr.ScriptsInit(); + sLog.outString("Validating spell scripts..."); + objmgr.ValidateSpellScripts(); + ///- Initialize game time and timers sLog.outDebug("DEBUG:: Initialize game time and timers"); m_gameTime = time(NULL); |
