/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Wietlol's Multi Cast Ability System 1.2 01/03/2015
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Description:
// This system is made to create a chain of abilities that can be cast in a specific order.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// How to install:
// 1. Copy or create all variables that are used in this map into your map.
// 1a. If you use vJASS then you can enable the MCA_vJASS_variables trigger and use that one.
// 1b. If you use GUI then you can use the MCA_GUI_variables trigger to automatically import them.
// 2. Copy the MCA_System trigger and paste it into your map.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// How to use:
// Create a chain:
// 1. Create a trigger for map initialization or use an existing one.
// 2. Set MCA_Original_Ability to the ability that the unit has by default.
// This one will fire the chain.
// 3. Set MCA_Amount to the number of abilities that the unit can cast after the first one.
// 4. Set all alternative abilities in MCA_Alternative_Ability[] in the correct order.
// 5. Set all durations that you are allowed to cast the alternative spell in MCS_Duration[].
// 6. Run MCA_System to create the chain. (Ignore conditions for performance.)
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Feature list:
// This system:
// - allows you to make a chain of abilities that can be cast after each other.
// - allows you to set a duration for each spell that the unit is allowed to cast it.
// - allows you to manually reset the chain of spells.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Variable explaination:
//////////////////////////
// Registration:
// - MCA_Hashtable - hashtable
// This is the hashtable that is used by the Multi Cast Ability System.
//
// - MCA_Amount - integer
// This is the number of alternative abilities that the original ability has in it's chain.
//
// - MCA_Original_Ability - ability (integer in JASS)
// This is the original ability that the unit has.
// This ability fires the chain.
//
// - MCA_Alternative_Ability - ability array (integer array in JASS)
// This is the list of abilities inside the chain.
//
// - MCA_Next_Spell_Chance - real array
// This is the list of the chance that the unit can cast the next spell.
//
// - MCA_Duration - real array
// This is the time in seconds that you can cast the second ability.
// When this time expires, the ability chain will reset to the original form.
//
// - MCA_Caster - unit
// This variable refers to the caster of the spells.
// This is used to reset the chain for the caster.
//
// - MCA_Trigger_Register_Chain - trigger
// This trigger registers the spells of a spell chain.
//
// - MCA_Trigger_Reset_Chain - trigger
// This trigger resets the chain to the original form of the targeted unit.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Changelog:
// 1.2 - New parameter: "Next Spell Chance".
// You can now apply a chance to be able to cast the next spell.
//
// 1.1 - New function: "Reset Chain".
// You can now reset the chain of a specific ability for a specific unit manually too.
//
// 1.0 - First official release on the Hive.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Known bugs:
// - None
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// These functions handle the temporary abilities.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//This function removes the last spell in the chain that is cast.
function MCA_Remove_Spells takes unit caster, integer lastSpell, integer originalSpell returns nothing
//It may not remove the original spell.
if lastSpell != originalSpell then
call UnitRemoveAbility(caster, lastSpell)
endif
//Enable the original spell.
call SetPlayerAbilityAvailable(GetOwningPlayer(caster), originalSpell, true)
endfunction
//This function removes the timer and the references for leak fixes.
function MCA_Reset_Abilities takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local unit caster = LoadUnitHandle(udg_MCA_Hashtable, id, 0)
local integer originalSpell = LoadInteger(udg_MCA_Hashtable, id, 1)
//Reset the abilities to the original form.
call MCA_Remove_Spells(caster, LoadInteger(udg_MCA_Hashtable, id, 3), originalSpell)
//Remove leaks.
call DestroyTimer(t)
call RemoveSavedHandle(udg_MCA_Hashtable, GetHandleId(caster), originalSpell)
call FlushChildHashtable(udg_MCA_Hashtable, id)
set caster = null
set t = null
endfunction
//This function gives the caster the next ability in the chain.
function MCA_Give_Alternative_Ability takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local unit caster = LoadUnitHandle(udg_MCA_Hashtable, id, 0)
local integer originalSpell = LoadInteger(udg_MCA_Hashtable, id, 1)
local integer lastSpell = LoadInteger(udg_MCA_Hashtable, id, 3)
local integer level = LoadInteger(udg_MCA_Hashtable, id, 2)
local integer newSpell = LoadInteger(udg_MCA_Hashtable, lastSpell, 1)
local real duration = LoadReal(udg_MCA_Hashtable, newSpell, 2)
local real chance = LoadReal(udg_MCA_Hashtable, lastSpell, 3)
if newSpell > 0 and GetRandomReal(0, 99.99) < chance then
//There is a next spell and the unit is able to cast it.
//Disable or remove the last cast spell.
if originalSpell == lastSpell then
call SetPlayerAbilityAvailable(GetOwningPlayer(caster), originalSpell, false)
else
call UnitRemoveAbility(caster, lastSpell)
endif
//Add the new spell.
call UnitAddAbility(caster, newSpell)
call SetUnitAbilityLevel(caster, newSpell, level)
//Update the timer that will reset the abilities.
call TimerStart(t, duration, false, function MCA_Reset_Abilities)
call SaveInteger(udg_MCA_Hashtable, id, 3, newSpell)
else
//There is no next spell.
//Reset the abilities to the original form.
call MCA_Remove_Spells(caster, lastSpell, originalSpell)
call DestroyTimer(t)
call RemoveSavedHandle(udg_MCA_Hashtable, GetHandleId(caster), originalSpell)
call FlushChildHashtable(udg_MCA_Hashtable, id)
endif
//Remove leaks.
set caster = null
set t = null
endfunction
//This function calls the next ability to pop up.
//This must be done after 0 seconds to ensure that the casting has ended properly.
function MCA_Multi_Cast_Effect takes nothing returns boolean
local integer spell = GetSpellAbilityId()
local unit caster = GetSpellAbilityUnit()
local integer level = GetUnitAbilityLevel(caster, spell)
local integer id = LoadInteger(udg_MCA_Hashtable, spell, 0)
local timer t
if id > 100 then
//The ability is cast as an alternative ability.
//Reset the timer and call the next ability.
set t = LoadTimerHandle(udg_MCA_Hashtable, GetHandleId(caster), id)
call TimerStart(t, 0, false, function MCA_Give_Alternative_Ability)
call SaveInteger(udg_MCA_Hashtable, GetHandleId(t), 3, spell)
set t = null
elseif id > 0 then
//Create a new timer that calls the next ability.
set t = CreateTimer()
call TimerStart(t, 0, false, function MCA_Give_Alternative_Ability)
set id = GetHandleId(t)
//Save the data to the timer.
call SaveUnitHandle(udg_MCA_Hashtable, id, 0, caster)
call SaveInteger(udg_MCA_Hashtable, id, 1, spell)
call SaveInteger(udg_MCA_Hashtable, id, 2, level)
call SaveInteger(udg_MCA_Hashtable, id, 3, spell)
call SaveTimerHandle(udg_MCA_Hashtable, GetHandleId(caster), spell, t)
set t = null
endif
//Remove leaks.
set caster = null
return false
endfunction
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// These are the functions that can be called manually.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//This function resets the chain of abilities.
function MCA_End_Timer takes nothing returns nothing
//Requires:
// - MCA_Original_Ability
// - MCA_Caster
call TimerStart(LoadTimerHandle(udg_MCA_Hashtable, GetHandleId(udg_MCA_Caster), udg_MCA_Original_Ability), 0, false, function MCA_Reset_Abilities)
endfunction
//This function registers the ability chain.
function MCA_Register_Multi_Cast_Spell takes nothing returns nothing
//Requires:
// - MCA_Original_Ability
// - MCA_Amount
// - MCA_Alternative_Ability[]
// - MCA_Next_Spell_Chance[]
// - MCA_Duration[]
local integer i = 1
local integer index = 0
//Save the first alternative ability to the chain.
call SaveInteger(udg_MCA_Hashtable, udg_MCA_Original_Ability, 0, udg_MCA_Amount)
call SaveInteger(udg_MCA_Hashtable, udg_MCA_Original_Ability, 1, udg_MCA_Alternative_Ability[0])
call SaveReal(udg_MCA_Hashtable, udg_MCA_Original_Ability, 3, udg_MCA_Next_Spell_Chance[0])
loop
//Save the duration and original ability to the hashtable.
call SaveInteger(udg_MCA_Hashtable, udg_MCA_Alternative_Ability[index], 0, udg_MCA_Original_Ability)
call SaveReal(udg_MCA_Hashtable, udg_MCA_Alternative_Ability[index], 2, udg_MCA_Duration[index])
exitwhen index >= udg_MCA_Amount-1
//Save the next ability in the chain.
call SaveInteger(udg_MCA_Hashtable, udg_MCA_Alternative_Ability[index], 1, udg_MCA_Alternative_Ability[index+1])
call SaveReal(udg_MCA_Hashtable, udg_MCA_Alternative_Ability[index], 3, udg_MCA_Next_Spell_Chance[index+1])
set i = i + 2
set index = index + 1
endloop
endfunction
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// This code is the initialization of the system.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//This is the initial function.
function InitTrig_MCA_System takes nothing returns nothing
//Create a trigger that will handle the multicast abilities.
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Filter(function MCA_Multi_Cast_Effect))
//Create a trigger that registers the ability chains.
set udg_MCA_Trigger_Register_Chain = CreateTrigger()
call TriggerAddAction(udg_MCA_Trigger_Register_Chain, function MCA_Register_Multi_Cast_Spell)
//Create a trigger that resets the ability chains.
set udg_MCA_Trigger_Reset_Chain = CreateTrigger()
call TriggerAddAction(udg_MCA_Trigger_Reset_Chain, function MCA_End_Timer)
//Create the hashtable that is used.
set udg_MCA_Hashtable = InitHashtable()
endfunction
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// MCA System end
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////