*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
This commit is contained in:
QAston
2010-07-24 22:41:42 +02:00
parent 687cd83bdd
commit 2352fc7cdf
30 changed files with 1253 additions and 14 deletions
+38 -2
View File
@@ -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;
}
}
+8
View File
@@ -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);
+215
View File
@@ -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;
}
+154
View File
@@ -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