This is a read only copy without any forum functionality of the old Modcraft forum.
If there is anything that you would like to have removed, message me on Discord via Kaev#5208.
Big thanks to Alastor for making this copy!

Menu

Author Topic: [WotLK][TC][Eluna][AIO] Custom secondary power types  (Read 2133 times)

Grymskvll

  • Registred Member
  • Polygonshifter
  • *****
  • Posts: 65
    • View Profile
[WotLK][TC][Eluna][AIO] Custom secondary power types
« on: August 16, 2016, 04:46:56 pm »
This is a system for custom secondary powertypes, like combo points, DK runes or spriests' shadow orbs. Here's a demo video, I previously posted it in the showoff thread:
[media:20r7yr4d]https://www.youtube.com/watch?v=qHSFOsNAs_A[/media:20r7yr4d]

If I forgot anything or if you have improvements, please let me know.

To use this, you need to have patched Wow.exe to load modified interface files. See http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-and-programs/501200-repost-sig-md5-protection-remover.html

First we need to add some Eluna player hooks for various stages of casting.
We need 3 new hooks:
PLAYER_EVENT_ON_SPELL_CAST_START   (validation and cancellation: script can return false to cancel the cast)
PLAYER_EVENT_ON_SPELL_CAST_SUCCESS   (spell passed normal checks for range, mana, target, etc, so now we do custom validation, but NO CHANGES ARE APPLIED in case a later script that registered this hook wants to cancel the cast)
PLAYER_EVENT_ON_SPELL_LAUNCH      (spell passed all custom validation from the previous hook, so here we can take custom power or do anything else without bugs)

To add these hooks, we need to modify various files. Hopefully it's not too disorienting. Make sure you don't have any uncommited changes before beginning!

In gameSpellsSpell.cpp, at the top of Spell::prepare, add the Eluna hook:
Code: [Select]
void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggeredByAura)
{

#ifdef ELUNA
if (Player* playerCaster = m_caster->ToPlayer())
{
if (!sEluna->OnSpellCastStart(playerCaster, this))
{
finish(false);
return;
}
}
#endif


In Spell::Cast, below "CallScriptOnCastHandlers();" add the Eluna hook:
Code: [Select]
CallScriptOnCastHandlers();


#ifdef ELUNA
if (Player* playerCaster = m_caster->ToPlayer())
{
if (!sEluna->OnSpellCastSuccess(playerCaster, this))
{
SendInterrupted(0);

if (playerCaster->GetTypeId() == TYPEID_PLAYER)
{
playerCaster->RestoreSpellMods(this);
// cleanup after mod system
// triggered spell pointer can be not removed in some cases
playerCaster->SetSpellModTakingSpell(this, false);
}
finish(false);
SetExecutedCurrently(false);

return;
}
}
#endif

At the top of Spell::HandleLaunchPhase(), add the Eluna hook:
Code: [Select]
void Spell::HandleLaunchPhase()
{
if (Player* playerCaster = m_caster->ToPlayer())
{
sScriptMgr->OnPlayerSpellLaunch(playerCaster, this);
}


In LuaEngineHeader FilesHooks.h, in "enum PlayerEvents" add:
Code: [Select]
PLAYER_EVENT_ON_SPELL_CAST_START =  43, // (event, player, spell)
PLAYER_EVENT_ON_SPELL_CAST_SUCCESS =  44, // (event, player, spell, skipCheck)
PLAYER_EVENT_ON_SPELL_LAUNCH =  45, // (event, player, spell)


In LuaEngineHeader FilesLuaEngine.h, add this under the "void OnTextEmote" declaration:
Code: [Select]
bool OnSpellCastStart(Player* pPlayer, Spell* pSpell);
bool OnSpellCastSuccess(Player* pPlayer, Spell* pSpell);
void OnSpellLaunch(Player* pPlayer, Spell* pSpell);


In LuaEngineSource FilesPlayerHooks.cpp, add the following:
Code: [Select]
bool Eluna::OnSpellCastStart(Player* pPlayer, Spell* pSpell)
{
START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_SPELL_CAST_START, true);
bool result = true;
Push(pPlayer);
Push(pSpell);
int n = SetupStack(PlayerEventBindings, key, 2);

while (n > 0)
{
int r = CallOneFunction(n--, 2, 1);

if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;

lua_pop(L, 1);
}

CleanUpStack(2);
return result;
}

bool Eluna::OnSpellCastSuccess(Player* pPlayer, Spell* pSpell)
{
START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_SPELL_CAST_SUCCESS, true);
bool result = true;
Push(pPlayer);
Push(pSpell);
int n = SetupStack(PlayerEventBindings, key, 2);

while (n > 0)
{
int r = CallOneFunction(n--, 2, 1);

if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;

lua_pop(L, 1);
}

CleanUpStack(2);
return result;
}

void Eluna::OnSpellLaunch(Player* pPlayer, Spell* pSpell)
{
START_HOOK(PLAYER_EVENT_ON_SPELL_LAUNCH);
Push(pPlayer);
Push(pSpell);
CallAllFunctions(PlayerEventBindings, key);
}


In gameScriptingScriptMgr.h, add this under the "virtual void OnTextEmote" declaration:
Code: [Select]
// Called in Spell::Prepare.
virtual void OnSpellCastStart(Player* /*player*/, Spell* /*spell*/) { }

// Called in Spell::Cast.
virtual void OnSpellCastSuccess(Player* /*player*/, Spell* /*spell*/) { }

// Called in Spell::HandleLaunchPhase.
virtual void OnSpellLaunch(Player* /*player*/, Spell* /*spell*/) { }

In gameScriptingScriptMgr.cpp, add:
Code: [Select]
void ScriptMgr::OnPlayerSpellCastStart(Player* player, Spell* spell)
{
#ifdef ELUNA
sEluna->OnSpellCastStart(player, spell);
#endif
FOREACH_SCRIPT(PlayerScript)->OnSpellCastStart(player, spell);
}

void ScriptMgr::OnPlayerSpellCastSuccess(Player* player, Spell* spell)
{
#ifdef ELUNA
sEluna->OnSpellCastSuccess(player, spell);
#endif
FOREACH_SCRIPT(PlayerScript)->OnSpellCastSuccess(player, spell);
}

void ScriptMgr::OnPlayerSpellLaunch(Player* player, Spell* spell)
{
#ifdef ELUNA
sEluna->OnSpellLaunch(player, spell);
#endif
FOREACH_SCRIPT(PlayerScript)->OnSpellLaunch(player, spell);
}


Next, we need to add a new Eluna spell method: SendCastResult. This is needed so that our Eluna script can send the player's client a notification to cancel the casting state and GCD, using castresult code 0 (SPELL_FAILED_SUCCESS), which has no error notification so we can jam in our custom "Not enough powertype" message separately. In hindsight, it might've been just as good to put a call to spell->SendCastResult inside Spell::prepare and Spell::Cast... oops.

In LuaEngineMethodsSpellMethods.h, within "namespace LuaSpell" add:
Code: [Select]
int SendCastResult(Eluna* /*E*/, lua_State* L, Spell* spell)
{
SpellCastResult result = (SpellCastResult)Eluna::CHECKVAL<uint32>(L, 2);
spell->SendCastResult(result);
return 0;
}

In LuaEngineSource FilesLuaFunctions.cpp, in ElunaRegister<Spell> SpellMethods[], add this under // Other:
Code: [Select]
{ "SendCastResult", &LuaSpell::SendCastResult },


To make spells that require the custom secondary power, create a spell with no power cost (the powertype shouldn't matter).

Finally, here's an archive with an MPQ required by each client that defines some custom secure vars and has some art required by the Happy Hearts example, as well as the AIO script with two example secondary powers included ("Happy Hearts" for the shaman, "Displeasure" for the warrior). The spell IDs in the examples are basic custom spells I made for testing. There's nothing special about them besides having 0 cost in Spell.dbc. Spell costs are handled in each power's own script file, in the "consuming" and "generating" tables. The Happy Hearts example has some comments. To make a new custom secondary power, copy one of the examples (Happy Hearts probably), and modify it to your needs (token, values at the top, update function, graphic setup). You don't need to change the main script file.

Mirror: https://a.fluntcaps.me/eakwpn.zip
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

Rochet2

  • Contributors
  • Polygonshifter
  • *****
  • Posts: 59
    • View Profile
    • http://rochet2.github.io/
Re: [WotLK][TC][Eluna][AIO] Custom secondary power types
« Reply #1 on: August 16, 2016, 05:03:16 pm »
Cute :3
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

Crow

  • Registred Member
  • GM Isle Explorer
  • *****
  • Posts: 18
    • View Profile
Re: [WotLK][TC][Eluna][AIO] Custom secondary power types
« Reply #2 on: October 08, 2016, 02:14:36 am »
hate to be a bother but is Eluna needed? couldnt this just be done without it?
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

Rochet2

  • Contributors
  • Polygonshifter
  • *****
  • Posts: 59
    • View Profile
    • http://rochet2.github.io/
Re: [WotLK][TC][Eluna][AIO] Custom secondary power types
« Reply #3 on: October 08, 2016, 10:01:05 am »
Quote from: "Crow"
hate to be a bother but is Eluna needed? couldnt this just be done without it?

No its not.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »