I'm trying to create spells which you can activate/deactivate like immolation without using an immolation-like spell as a base. Why would I want to do that? I want spells which have the following attributes:
- targetable (unit or point)
- cost mana over time
- can be deactivated at will
- is not channeled
My current method:
remove the targetable spell on cast
add a spell which takes no target and does nothing on itself
trigger all the effects
if the other spell is cast, remove it and readd the targetable spell
The problem with this is, that if you try to spend another skill point on this spell while it's activated you learn the ability another time instead of leveling it up.
Now my actual question: Is there any way to avoid this glitch without using engineering upgrade?
- targetable (unit or point)
- cost mana over time
- can be deactivated at will
- is not channeled
My current method:
remove the targetable spell on cast
add a spell which takes no target and does nothing on itself
trigger all the effects
if the other spell is cast, remove it and readd the targetable spell
The problem with this is, that if you try to spend another skill point on this spell while it's activated you learn the ability another time instead of leveling it up.
Now my actual question: Is there any way to avoid this glitch without using engineering upgrade?
Prove of Concept - Recreating Immolation
JASS:
//! zinc
library ActivatableSpell requires SpellEvent
{
Table Ability2Order;
function onEffect ()
{
integer id = GetSpellAbilityId();
unit whichUnit = GetTriggerUnit();
if (Ability2Order.exists(id))
{
UnitRemoveAbility(whichUnit,id);
UnitAddAbility(whichUnit,Ability2Order[id]);
}
}
public function RegisterActivatableSpell (integer BaseId, SpellEvent_Response onActivate, integer AuxId, SpellEvent_Response onDeactivate)
{
Ability2Order[BaseId] = AuxId;
RegisterSpellEffectResponse(BaseId,onActivate);
Ability2Order[AuxId] = BaseId;
RegisterSpellEffectResponse(AuxId,onDeactivate);
}
function onInit ()
{
trigger t = CreateTrigger();
TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT);
TriggerAddAction(t,function onEffect);
Ability2Order = Table.create();
}
}
//! endzinc
JASS:
//! zinc
library Immolation requires ActivatableSpell, ABuff
{
constant integer SpellId = 039;A000039;;
constant integer AuxId = 039;A001039;;
constant integer AuraId = 039;C000039;;
constant integer BuffId = 039;BEim039;;
aBuffType BuffType;
constant string BurnFx = "Abilities\\Spells\\NightElf\\Immolation\\ImmolationDamage.mdl";
function getRange (integer level) -> real
{
return 160.;
}
function getBurnDamage (integer level) -> real
{
return (5.+5*level)*ABuff_PERIODIC_EVENT_PERIOD;
}
function getPeriodicCost (integer level) -> real
{
return 7.*ABuff_PERIODIC_EVENT_PERIOD;
}
function getManaThreshold (integer level) -> real
{
return 10.;
}
function targetFilter () -> boolean
{
unit u = GetFilterUnit();
boolean b = IsUnitType(u,UNIT_TYPE_GROUND)==true && IsUnitEnemy(u,bj_groupEnumOwningPlayer)==true && IsUnitType(u,UNIT_TYPE_MECHANICAL)==false && IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)==false;
u = null;
return b;
}
function onCreate (aBuff eventBuff)
{
BuffType.display.apply(eventBuff.target.u,eventBuff.level);
}
function onCleanup (aBuff eventBuff)
{
BuffType.display.remove(eventBuff.target.u);
}
function onPeriodic (aBuff eventBuff)
{
real damage = getBurnDamage(eventBuff.level);
unit f;
bj_groupEnumOwningPlayer = GetOwningPlayer(eventBuff.target.u);
GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(eventBuff.target.u),GetUnitY(eventBuff.target.u),getRange(eventBuff.level),Filter(function targetFilter));
f = FirstOfGroup(ENUM_GROUP);
while (f!=null)
{
GroupRemoveUnit(ENUM_GROUP,f);
DestroyEffect(AddSpecialEffectTarget(BurnFx,f,"head"));
UnitDamageTargetEx(eventBuff.target.u, f, damage, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_SPELL, true);
f = FirstOfGroup(ENUM_GROUP);
}
SetUnitState(eventBuff.target.u,UNIT_STATE_MANA,GetUnitState(eventBuff.target.u,UNIT_STATE_MANA)-getPeriodicCost(eventBuff.level));
if (GetUnitState(eventBuff.target.u,UNIT_STATE_MANA)<getManaThreshold(eventBuff.level))
{
ABuffRemove(eventBuff);
}
}
function onActivate ()
{
ABuffApply(BuffType,SpellEvent.TargetUnit,SpellEvent.CastingUnit,0,SpellEvent.SpellLevel,0);
}
function onDeactivate ()
{
ABuffRemove(GetABuffFromUnitByType(SpellEvent.CastingUnit,BuffType));
}
function onInit ()
{
RegisterActivatableSpell(SpellId,onActivate,AuxId,onDeactivate);
BuffType = aBuffType.create();
BuffType.eventCreate = onCreate;
BuffType.eventCleanup = onCleanup;
BuffType.eventPeriodic = onPeriodic;
BuffType.display = aBuffDisplay.create(AuraId,BuffId);
}
}
//! endzinc