diff options
| -rw-r--r-- | sql/scripts/world_scripts_full.sql | 5 | ||||
| -rw-r--r-- | sql/updates/world/2011_03_04_1_world_spell_script_names.sql | 8 | ||||
| -rwxr-xr-x | src/server/game/Miscellaneous/SharedDefines.h | 84 | ||||
| -rwxr-xr-x | src/server/game/Skills/SkillDiscovery.cpp | 16 | ||||
| -rwxr-xr-x | src/server/game/Skills/SkillDiscovery.h | 1 | ||||
| -rwxr-xr-x | src/server/game/Spells/Spell.cpp | 32 | ||||
| -rwxr-xr-x | src/server/game/Spells/Spell.h | 4 | ||||
| -rwxr-xr-x | src/server/game/Spells/SpellEffects.cpp | 2 | ||||
| -rwxr-xr-x | src/server/game/Spells/SpellScript.cpp | 21 | ||||
| -rwxr-xr-x | src/server/game/Spells/SpellScript.h | 29 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_generic.cpp | 34 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_item.cpp | 34 |
12 files changed, 262 insertions, 8 deletions
diff --git a/sql/scripts/world_scripts_full.sql b/sql/scripts/world_scripts_full.sql index e962a3453ec..88c07e6e003 100644 --- a/sql/scripts/world_scripts_full.sql +++ b/sql/scripts/world_scripts_full.sql @@ -1847,6 +1847,10 @@ INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES ( 72706, 'spell_gen_dungeon_credit'), ( 72830, 'spell_gen_dungeon_credit'), ( 72959, 'spell_gen_dungeon_credit'), +( 60893, 'spell_gen_profession_research'), +( 61177, 'spell_gen_profession_research'), +( 61288, 'spell_gen_profession_research'), +( 61756, 'spell_gen_profession_research'), -- instances -- Black Temple ( 41475, 'spell_boss_lady_malande_shield'), @@ -2103,6 +2107,7 @@ INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES ( 71905, 'spell_item_shadowmourne'), ( 67533, 'spell_item_red_rider_air_rifle'), ( 26678, 'spell_item_create_heart_candy'), +( 64323, 'spell_item_book_of_glyph_mastery'), -- warrior ( 12975, 'spell_warr_last_stand'), ( 59725, 'spell_warr_improved_spell_reflection'), diff --git a/sql/updates/world/2011_03_04_1_world_spell_script_names.sql b/sql/updates/world/2011_03_04_1_world_spell_script_names.sql new file mode 100644 index 00000000000..db399ebd042 --- /dev/null +++ b/sql/updates/world/2011_03_04_1_world_spell_script_names.sql @@ -0,0 +1,8 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_gen_profession_research'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_item_book_of_glyph_mastery'; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(60893, 'spell_gen_profession_research'), +(61177, 'spell_gen_profession_research'), +(61288, 'spell_gen_profession_research'), +(61756, 'spell_gen_profession_research'), +(64323, 'spell_item_book_of_glyph_mastery'); diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index fade7de99bf..25011abc64d 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -1007,6 +1007,90 @@ enum SpellCastResult SPELL_CAST_OK = 255 // custom value, don't must be send to client }; +enum SpellCustomErrors +{ + SPELL_CUSTOM_ERROR_NONE = 0, + SPELL_CUSTOM_ERROR_CUSTOM_MSG = 1, // Something bad happened, and we want to display a custom message! + SPELL_CUSTOM_ERROR_ALEX_BROKE_QUEST = 2, // Alex broke your quest! Thank him later! + SPELL_CUSTOM_ERROR_NEED_HELPLESS_VILLAGER = 3, // This spell may only be used on Helpless Wintergarde Villagers that have not been rescued. + SPELL_CUSTOM_ERROR_NEED_WARSONG_DISGUISE = 4, // Requires that you be wearing the Warsong Orc Disguise. + SPELL_CUSTOM_ERROR_REQUIRES_PLAGUE_WAGON = 5, // You must be closer to a plague wagon in order to drop off your 7th Legion Siege Engineer. + SPELL_CUSTOM_ERROR_CANT_TARGET_FRIENDLY_NONPARTY = 6, // You cannot target friendly units outside your party. + SPELL_CUSTOM_ERROR_NEED_CHILL_NYMPH = 7, // You must target a weakened chill nymph. + SPELL_CUSTOM_ERROR_MUST_BE_IN_ENKILAH = 8, // The Imbued Scourge Shroud will only work when equipped in the Temple City of En'kilah. + SPELL_CUSTOM_ERROR_REQUIRES_CORPSE_DUST = 9, // Requires Corpse Dust + SPELL_CUSTOM_ERROR_CANT_SUMMON_GARGOYLE = 10, // You cannot summon another gargoyle yet. + SPELL_CUSTOM_ERROR_NEED_CORPSE_DUST_IF_NO_TARGET = 11, // Requires Corpse Dust if the target is not dead and humanoid. + SPELL_CUSTOM_ERROR_MUST_BE_AT_SHATTERHORN = 12, // Can only be placed near Shatterhorn + SPELL_CUSTOM_ERROR_MUST_TARGET_PROTO_DRAKE_EGG = 13, // You must first select a Proto-Drake Egg. + SPELL_CUSTOM_ERROR_MUST_BE_CLOSE_TO_TREE = 14, // You must be close to a marked tree. + SPELL_CUSTOM_ERROR_MUST_TARGET_TURKEY = 15, // You must target a Fjord Turkey. + SPELL_CUSTOM_ERROR_MUST_TARGET_HAWK = 16, // You must target a Fjord Hawk. + SPELL_CUSTOM_ERROR_TOO_FAR_FROM_BOUY = 17, // You are too far from the bouy. + SPELL_CUSTOM_ERROR_MUST_BE_CLOSE_TO_OIL_SLICK = 18, // Must be used near an oil slick. + SPELL_CUSTOM_ERROR_MUST_BE_CLOSE_TO_BOUY = 19, // You must be closer to the buoy! + SPELL_CUSTOM_ERROR_WYRMREST_VANQUISHER = 20, // You may only call for the aid of a Wyrmrest Vanquisher in Wyrmrest Temple, The Dragon Wastes, Galakrond's Rest or The Wicked Coil. + SPELL_CUSTOM_ERROR_MUST_TARGET_ICE_HEART_JORMUNGAR = 21, // That can only be used on a Ice Heart Jormungar Spawn. + SPELL_CUSTOM_ERROR_MUST_BE_CLOSE_TO_SINKHOLE = 22, // You must be closer to a sinkhole to use your map. + SPELL_CUSTOM_ERROR_REQUIRES_HAROLD_LANE = 23, // You may only call down a stampede on Harold Lane. + SPELL_CUSTOM_ERROR_REQUIRES_GAMMOTH_MAGNATAUR = 24, // You may only use the Pouch of Crushed Bloodspore on Gammothra or other magnataur in the Bloodspore Plains and Gammoth. + SPELL_CUSTOM_ERROR_MUST_BE_IN_RESURRECTION_CHAMBER = 25, // Requires the magmawyrm resurrection chamber in the back of the Maw of Neltharion. + SPELL_CUSTOM_ERROR_CANT_CALL_WINTERGARDE_HERE = 26, // You may only call down a Wintergarde Gryphon in Wintergarde Keep or the Carrion Fields. + SPELL_CUSTOM_ERROR_MUST_TARGET_WILHELM = 27, // What are you doing? Only aim that thing at Wilhelm! + SPELL_CUSTOM_ERROR_NOT_ENOUGH_HEALTH = 28, // Not enough health! + SPELL_CUSTOM_ERROR_NO_NEARBY_CORPSES = 29, // There are no nearby corpses to use + SPELL_CUSTOM_ERROR_TOO_MANY_GHOULS = 30, // You've created enough ghouls. Return to Gothik the Harvester at Death's Breach. + SPELL_CUSTOM_ERROR_GO_FURTHER_FROM_SUNDERED_SHARD = 31, // Your companion does not want to come here. Go further from the Sundered Shard. + SPELL_CUSTOM_ERROR_MUST_BE_IN_CAT_FORM = 32, // Must be in Cat Form + SPELL_CUSTOM_ERROR_MUST_BE_DEATH_KNIGHT = 33, // Only Death Knights may enter Ebon Hold. + SPELL_CUSTOM_ERROR_MUST_BE_IN_FERAL_FORM = 34, // Must be in Cat Form, Bear Form, or Dire Bear Form + SPELL_CUSTOM_ERROR_MUST_BE_NEAR_HELPLESS_VILLAGER = 35, // You must be within range of a Helpless Wintergarde Villager. + SPELL_CUSTOM_ERROR_MUST_TARGET_ELEMENTAL_MECHANICAL = 36, // You cannot target an elemental or mechanical corpse. + SPELL_CUSTOM_ERROR_MUST_HAVE_USED_DALARAN_CRYSTAL = 37, // This teleport crystal cannot be used until the teleport crystal in Dalaran has been used at least once. + SPELL_CUSTOM_ERROR_YOU_ALREADY_HOLD_SOMETHING = 38, // You are already holding something in your hand. You must throw the creature in your hand before picking up another. + SPELL_CUSTOM_ERROR_YOU_DONT_HOLD_ANYTHING = 39, // You don't have anything to throw! Find a Vargul and use Gymer Grab to pick one up! + SPELL_CUSTOM_ERROR_MUST_BE_CLOSE_TO_VALDURAN = 40, // Bouldercrag's War Horn can only be used within 10 yards of Valduran the Stormborn. + SPELL_CUSTOM_ERROR_NO_PASSENGER = 41, // You are not carrying a passenger. There is nobody to drop off. + SPELL_CUSTOM_ERROR_CANT_BUILD_MORE_VEHICLES = 42, // You cannot build any more siege vehicles. + SPELL_CUSTOM_ERROR_ALREADY_CARRYING_CRUSADER = 43, // You are already carrying a captured Argent Crusader. You must return to the Argent Vanguard infirmary and drop off your passenger before you may pick up another. + SPELL_CUSTOM_ERROR_CANT_DO_WHILE_ROOTED = 44, // You can't do that while rooted. + SPELL_CUSTOM_ERROR_REQUIRES_NEARBY_TARGET = 45, // Requires a nearby target. + SPELL_CUSTOM_ERROR_NOTHING_TO_DISCOVER = 46, // Nothing left to discover. + SPELL_CUSTOM_ERROR_NOT_ENOUGH_TARGETS = 47, // No targets close enough to bluff. + SPELL_CUSTOM_ERROR_CONSTRUCT_TOO_FAR = 48, // Your Iron Rune Construct is out of range. + SPELL_CUSTOM_ERROR_REQUIRES_GRAND_MASTER_ENGINEER = 49, // Requires Grand Master Engineer + SPELL_CUSTOM_ERROR_CANT_USE_THAT_MOUNT = 50, // You can't use that mount. + SPELL_CUSTOM_ERROR_NOONE_TO_EJECT = 51, // There is nobody to eject! + SPELL_CUSTOM_ERROR_TARGET_MUST_BE_BOUND = 52, // The target must be bound to you. + SPELL_CUSTOM_ERROR_TARGET_MUST_BE_UNDEAD = 53, // Target must be undead. + SPELL_CUSTOM_ERROR_TARGET_TOO_FAR = 54, // You have no target or your target is too far away. + SPELL_CUSTOM_ERROR_MISSING_DARK_MATTER = 55, // Missing Reagents: Dark Matter + SPELL_CUSTOM_ERROR_CANT_USE_THAT_ITEM = 56, // You can't use that item + SPELL_CUSTOM_ERROR_CANT_DO_WHILE_CYCYLONED = 57, // You can't do that while Cycloned + SPELL_CUSTOM_ERROR_TARGET_HAS_SCROLL = 58, // Target is already affected by a scroll + SPELL_CUSTOM_ERROR_POISON_TOO_STRONG = 59, // That anti-venom is not strong enough to dispel that poison + SPELL_CUSTOM_ERROR_MUST_HAVE_LANCE_EQUIPPED = 60, // You must have a lance equipped. + SPELL_CUSTOM_ERROR_MUST_BE_CLOSE_TO_MAIDEN = 61, // You must be near the Maiden of Winter's Breath Lake. + SPELL_CUSTOM_ERROR_LEARNED_EVERYTHING = 62, // You have learned everything from that book + SPELL_CUSTOM_ERROR_PET_IS_DEAD = 63, // Your pet is dead + SPELL_CUSTOM_ERROR_NO_VALID_TARGETS = 64, // There are no valid targets within range. + SPELL_CUSTOM_ERROR_GM_ONLY = 65, // Only GMs may use that. Your account has been reported for investigation. + SPELL_CUSTOM_ERROR_REQUIRES_LEVEL_58 = 66, // You must reach level 58 to use this portal. + SPELL_CUSTOM_ERROR_AT_HONOR_CAP = 67, // You already have the maximum amount of honor. + SPELL_CUSTOM_ERROR_MUST_HAVE_DEMONIC_CIRCLE = 75, // You must have a demonic circle active. + SPELL_CUSTOM_ERROR_AT_MAX_RAGE = 76, // You already have maximum rage + SPELL_CUSTOM_ERROR_REQUIRES_350_ENGINEERING = 77, // Requires Engineering (350) + SPELL_CUSTOM_ERROR_SOUL_BELONGS_TO_LICH_KING = 78, // Your soul belongs to the Lich King + SPELL_CUSTOM_ERROR_ATTENDANT_HAS_PONY = 79, // Your attendant already has an Argent Pony + SPELL_CUSTOM_ERROR_MUST_HAVE_FIRE_TOTEM = 83, // You must have a Fire Totem active. + SPELL_CUSTOM_ERROR_CANT_TARGET_VAMPIRES = 84, // You may not bite other vampires. + SPELL_CUSTOM_ERROR_PET_ALREADY_AT_YOUR_LEVEL = 85, // Your pet is already at your level. + SPELL_CUSTOM_ERROR_MISSING_ITEM_REQUIREMENS = 86, // You do not meet the level requirements for this item. + SPELL_CUSTOM_ERROR_TOO_MANY_ABOMINATIONS = 87, // There are too many Mutated Abominations. + SPELL_CUSTOM_ERROR_ALL_POTIONS_USED = 88, // The potions have all been depleted by Professor Putricide. + SPELL_CUSTOM_ERROR_REQUIRES_LEVEL_65 = 90, // Requires level 65 +}; + enum StealthType { STEALTH_GENERAL = 0, diff --git a/src/server/game/Skills/SkillDiscovery.cpp b/src/server/game/Skills/SkillDiscovery.cpp index c75d34079b6..c2af8dd1e48 100755 --- a/src/server/game/Skills/SkillDiscovery.cpp +++ b/src/server/game/Skills/SkillDiscovery.cpp @@ -191,6 +191,22 @@ uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player) return 0; } +bool HasDiscoveredAllSpells(uint32 spellId, Player* player) +{ + SkillDiscoveryMap::const_iterator tab = SkillDiscoveryStore.find(spellId); + if (tab == SkillDiscoveryStore.end()) + return true; + + SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId); + uint32 skillvalue = bounds.first != bounds.second ? player->GetSkillValue(bounds.first->second->skillId) : 0; + + for (SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter) + if (!player->HasSpell(item_iter->spellId)) + return false; + + return true; +} + uint32 GetSkillDiscoverySpell(uint32 skillId, uint32 spellId, Player* player) { uint32 skillvalue = skillId ? player->GetSkillValue(skillId) : 0; diff --git a/src/server/game/Skills/SkillDiscovery.h b/src/server/game/Skills/SkillDiscovery.h index da9a96c4bd9..ae4f3494534 100755 --- a/src/server/game/Skills/SkillDiscovery.h +++ b/src/server/game/Skills/SkillDiscovery.h @@ -25,6 +25,7 @@ class Player; void LoadSkillDiscoveryTable(); uint32 GetSkillDiscoverySpell(uint32 skillId, uint32 spellId, Player* player); +bool HasDiscoveredAllSpells(uint32 spellId, Player* player); uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player); #endif diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index b89e1167f2c..e1f16e50be0 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -425,6 +425,7 @@ m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, Caster)), m_caster(Caster), m_spellValue(new SpellValue(m_spellInfo)) { m_customAttr = sSpellMgr->GetSpellCustomAttr(m_spellInfo->Id); + m_customError = SPELL_CUSTOM_ERROR_NONE; m_skipCheck = skipCheck; m_selfContainer = NULL; m_referencedFromCurrentSpell = false; @@ -3742,10 +3743,10 @@ void Spell::SendCastResult(SpellCastResult result) if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time return; - SendCastResult((Player*)m_caster,m_spellInfo,m_cast_count,result); + SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError); } -void Spell::SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result) +void Spell::SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/) { if (result == SPELL_CAST_OK) return; @@ -3807,6 +3808,9 @@ void Spell::SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 ca data << uint32(pProto->ItemLimitCategory); break; } + case SPELL_FAILED_CUSTOM_ERROR: + data << uint32(customError); + break; default: break; } @@ -5009,6 +5013,11 @@ SpellCastResult Spell::CheckCast(bool strict) return castResult; } + // script hook + castResult = CallScriptCheckCastHandlers(); + if (castResult != SPELL_CAST_OK) + return castResult; + for (int i = 0; i < MAX_SPELL_EFFECTS; i++) { // for effects of spells that have only one target @@ -7216,6 +7225,25 @@ void Spell::PrepareScriptHitHandlers() (*scritr)->_InitHit(); } +SpellCastResult Spell::CallScriptCheckCastHandlers() +{ + SpellCastResult retVal = SPELL_CAST_OK; + for (std::list<SpellScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CHECK_CAST); + std::list<SpellScript::CheckCastHandler>::iterator hookItrEnd = (*scritr)->OnCheckCast.end(), hookItr = (*scritr)->OnCheckCast.begin(); + for (; hookItr != hookItrEnd; ++hookItr) + { + SpellCastResult tempResult = (*hookItr).Call(*scritr); + if (retVal == SPELL_CAST_OK) + retVal = tempResult; + } + + (*scritr)->_FinishScriptCall(); + } + return retVal; +} + bool Spell::CallScriptEffectHandlers(SpellEffIndex effIndex) { // execute script effect handler hooks and check if effects was prevented diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index d83107f1db3..55b8d38820a 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -470,7 +470,7 @@ class Spell void CheckSrc() { if (!m_targets.HasSrc()) m_targets.setSrc(*m_caster); } void CheckDst() { if (!m_targets.HasDst()) m_targets.setDst(*m_caster); } - static void SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result); + static void SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE); void SendCastResult(SpellCastResult result); void SendSpellStart(); void SendSpellGo(); @@ -503,6 +503,7 @@ class Spell uint32 m_preCastSpell; SpellCastTargets m_targets; int8 m_comboPointGain; + SpellCustomErrors m_customError; UsedSpellMods m_appliedMods; @@ -687,6 +688,7 @@ class Spell // Scripting system void LoadScripts(); + SpellCastResult CallScriptCheckCastHandlers(); void PrepareScriptHitHandlers(); bool CallScriptEffectHandlers(SpellEffIndex effIndex); void CallScriptBeforeHitHandlers(); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index d2709c1d4d1..984895b85db 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -5126,7 +5126,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) return; // learn random explicit discovery recipe (if any) - if (uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, (Player*)m_caster)) + if (uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, m_caster->ToPlayer())) m_caster->ToPlayer()->learnSpell(discoveredSpell, false); return; } diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 52a06bd1f2e..fcb3bef7e30 100755 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -146,6 +146,16 @@ std::string _SpellScript::EffectAuraNameCheck::ToString() } } +SpellScript::CheckCastHandler::CheckCastHandler(SpellCheckCastFnType checkCastHandlerScript) +{ + _checkCastHandlerScript = checkCastHandlerScript; +} + +SpellCastResult SpellScript::CheckCastHandler::Call(SpellScript* spellScript) +{ + return (spellScript->*_checkCastHandlerScript)(); +} + SpellScript::EffectHandler::EffectHandler(SpellEffectFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName) : _SpellScript::EffectNameCheck(_effName), _SpellScript::EffectHook(_effIndex) { @@ -445,6 +455,17 @@ void SpellScript::FinishCast(SpellCastResult result) m_spell->finish(result == SPELL_CAST_OK); } +void SpellScript::SetCustomCastResultMessage(SpellCustomErrors result) +{ + if (!IsInCheckCastHook()) + { + sLog->outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::SetCustomCastResultMessage was called while spell not in check cast phase!", m_scriptName->c_str(), m_scriptSpellId); + return; + } + + m_spell->m_customError = result; +} + bool AuraScript::_Validate(SpellEntry const * entry) { for (std::list<EffectApplyHandler>::iterator itr = OnEffectApply.begin(); itr != OnEffectApply.end(); ++itr) diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 6a57befef41..4510b1b9f3b 100755 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -121,11 +121,12 @@ enum SpellScriptHookType SPELL_SCRIPT_HOOK_HIT, SPELL_SCRIPT_HOOK_AFTER_HIT, SPELL_SCRIPT_HOOK_UNIT_TARGET_SELECT, + SPELL_SCRIPT_HOOK_CHECK_CAST, }; #define HOOK_SPELL_HIT_START SPELL_SCRIPT_HOOK_EFFECT #define HOOK_SPELL_HIT_END SPELL_SCRIPT_HOOK_AFTER_HIT + 1 #define HOOK_SPELL_START SPELL_SCRIPT_HOOK_EFFECT -#define HOOK_SPELL_END SPELL_SCRIPT_HOOK_UNIT_TARGET_SELECT + 1 +#define HOOK_SPELL_END SPELL_SCRIPT_HOOK_CHECK_CAST + 1 #define HOOK_SPELL_COUNT HOOK_SPELL_END - HOOK_SPELL_START class SpellScript : public _SpellScript @@ -134,12 +135,22 @@ class SpellScript : public _SpellScript // DO NOT OVERRIDE THESE IN SCRIPTS public: #define SPELLSCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) \ + typedef SpellCastResult(CLASSNAME::*SpellCheckCastFnType)(); \ typedef void(CLASSNAME::*SpellEffectFnType)(SpellEffIndex); \ typedef void(CLASSNAME::*SpellHitFnType)(); \ typedef void(CLASSNAME::*SpellUnitTargetFnType)(std::list<Unit*>&); \ SPELLSCRIPT_FUNCTION_TYPE_DEFINES(SpellScript) + class CheckCastHandler + { + public: + CheckCastHandler(SpellCheckCastFnType checkCastHandlerScript); + SpellCastResult Call(SpellScript* spellScript); + private: + SpellCheckCastFnType _checkCastHandlerScript; + }; + class EffectHandler : public _SpellScript::EffectNameCheck, public _SpellScript::EffectHook { public: @@ -173,6 +184,7 @@ class SpellScript : public _SpellScript }; #define SPELLSCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) \ + class CheckCastHandlerFunction : public SpellScript::CheckCastHandler { public: CheckCastHandlerFunction(SpellCheckCastFnType _checkCastHandlerScript) : SpellScript::CheckCastHandler((SpellScript::SpellCheckCastFnType)_checkCastHandlerScript) {} }; \ class EffectHandlerFunction : public SpellScript::EffectHandler { public: EffectHandlerFunction(SpellEffectFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName) : SpellScript::EffectHandler((SpellScript::SpellEffectFnType)_pEffectHandlerScript, _effIndex, _effName) {} }; \ class HitHandlerFunction : public SpellScript::HitHandler { public: HitHandlerFunction(SpellHitFnType _pHitHandlerScript) : SpellScript::HitHandler((SpellScript::SpellHitFnType)_pHitHandlerScript) {} }; \ class UnitTargetHandlerFunction : public SpellScript::UnitTargetHandler { public: UnitTargetHandlerFunction(SpellUnitTargetFnType _pUnitTargetHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::UnitTargetHandler((SpellScript::SpellUnitTargetFnType)_pUnitTargetHandlerScript, _effIndex, _targetType) {} }; \ @@ -186,8 +198,9 @@ class SpellScript : public _SpellScript bool _IsDefaultEffectPrevented(SpellEffIndex effIndex) { return m_hitPreventDefaultEffectMask & (1<<effIndex); } void _PrepareScriptCall(SpellScriptHookType hookType); void _FinishScriptCall(); - bool IsInHitPhase() { return (m_currentScriptState >= HOOK_SPELL_HIT_START && m_currentScriptState < HOOK_SPELL_HIT_END); } - bool IsInEffectHook() { return (m_currentScriptState == SPELL_SCRIPT_HOOK_EFFECT); } + bool IsInCheckCastHook() const { return m_currentScriptState == SPELL_SCRIPT_HOOK_CHECK_CAST; } + bool IsInHitPhase() const { return (m_currentScriptState >= HOOK_SPELL_HIT_START && m_currentScriptState < HOOK_SPELL_HIT_END); } + bool IsInEffectHook() const { return (m_currentScriptState == SPELL_SCRIPT_HOOK_EFFECT); } private: Spell * m_spell; uint8 m_hitPreventEffectMask; @@ -197,6 +210,12 @@ class SpellScript : public _SpellScript // SpellScript interface // hooks to which you can attach your functions // + + // example: OnCheckCast += SpellCheckCastFn(); + // where function is SpellCastResult function() + HookList<CheckCastHandler> OnCheckCast; + #define SpellCheckCastFn(F) CheckCastHandlerFunction(&F) + // example: OnEffect += SpellEffectFn(class::function, EffectIndexSpecifier, EffectNameSpecifier); // where function is void function(SpellEffIndex effIndex) HookList<EffectHandler> OnEffect; @@ -294,6 +313,8 @@ class SpellScript : public _SpellScript // finishes spellcast prematurely with selected error message void FinishCast(SpellCastResult result); + + void SetCustomCastResultMessage(SpellCustomErrors result); }; // AuraScript interface - enum used for runtime checks of script function calls @@ -454,7 +475,7 @@ class AuraScript : public _SpellScript // executed when periodic aura effect is updated // example: OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); - // where function is: void function (AuraEffect const * aurEff); + // where function is: void function (AuraEffect * aurEff); HookList<EffectUpdatePeriodicHandler> OnEffectUpdatePeriodic; #define AuraEffectUpdatePeriodicFn(F, I, N) EffectUpdatePeriodicHandlerFunction(&F, I, N) diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 5befce55949..63df688b92f 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -24,6 +24,7 @@ #include "ScriptPCH.h" #include "SpellAuraEffects.h" +#include "SkillDiscovery.h" class spell_gen_absorb0_hitlimit1 : public SpellScriptLoader { @@ -766,6 +767,38 @@ class spell_gen_dungeon_credit : public SpellScriptLoader } }; +class spell_gen_profession_research : public SpellScriptLoader +{ + public: + spell_gen_profession_research() : SpellScriptLoader("spell_gen_profession_research") {} + + class spell_gen_profession_research_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_profession_research_SpellScript); + + SpellCastResult CheckRequirement() + { + if (GetCaster()->GetTypeId() == TYPEID_PLAYER && HasDiscoveredAllSpells(GetSpellInfo()->Id, GetCaster()->ToPlayer())) + { + SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_NOTHING_TO_DISCOVER); + return SPELL_FAILED_CUSTOM_ERROR; + } + + return SPELL_CAST_OK; + } + + void Register() + { + OnCheckCast += SpellCheckCastFn(spell_gen_profession_research_SpellScript::CheckRequirement); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_profession_research_SpellScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -785,4 +818,5 @@ void AddSC_generic_spell_scripts() new spell_gen_parachute_ic(); new spell_gen_gunship_portal(); new spell_gen_dungeon_credit(); + new spell_gen_profession_research(); } diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 43589c68180..4cffbdf4437 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -22,6 +22,7 @@ */ #include "ScriptPCH.h" +#include "SkillDiscovery.h" // Generic script for handling item dummy effects which trigger another spell. class spell_item_trigger_spell : public SpellScriptLoader @@ -849,6 +850,38 @@ class spell_item_create_heart_candy : public SpellScriptLoader } }; +class spell_item_book_of_glyph_mastery : public SpellScriptLoader +{ + public: + spell_item_book_of_glyph_mastery() : SpellScriptLoader("spell_item_book_of_glyph_mastery") {} + + class spell_item_book_of_glyph_mastery_SpellScript : public SpellScript + { + PrepareSpellScript(spell_item_book_of_glyph_mastery_SpellScript); + + SpellCastResult CheckRequirement() + { + if (GetCaster()->GetTypeId() == TYPEID_PLAYER && HasDiscoveredAllSpells(GetSpellInfo()->Id, GetCaster()->ToPlayer())) + { + SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_LEARNED_EVERYTHING); + return SPELL_FAILED_CUSTOM_ERROR; + } + + return SPELL_CAST_OK; + } + + void Register() + { + OnCheckCast += SpellCheckCastFn(spell_item_book_of_glyph_mastery_SpellScript::CheckRequirement); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_item_book_of_glyph_mastery_SpellScript(); + } +}; + void AddSC_item_spell_scripts() { // 23074 Arcanite Dragonling @@ -874,4 +907,5 @@ void AddSC_item_spell_scripts() new spell_item_red_rider_air_rifle(); new spell_item_create_heart_candy(); + new spell_item_book_of_glyph_mastery(); } |
