public static class Spell {
public static Ability Ability;
private static bool SkipSpellStop;
public static void Init() {
PlayerUnitEvents.Register(PlayerUnitEvent.SpellChannel, SpellBegin);
PlayerUnitEvents.Register(PlayerUnitEvent.UnitTypeReceivesOrder, SpellStop);
}
private static void SpellBegin() {
var hero = GetHero(GetTriggerUnit());
hero.abilityCast = GetSpellAbility();
hero.abilityCastId = GetSpellAbilityId();
hero.AbilityDict[hero.abilityCastId].CasterX = GetUnitX(hero.unit);
hero.AbilityDict[hero.abilityCastId].CasterY = GetUnitY(hero.unit);
if (hero.AbilityDict[hero.abilityCastId].Option == Options.Instant) {
// Call the ability method
BlzStartUnitAbilityCooldown(hero.unit, hero.abilityCastId, hero.AbilityDict[hero.abilityCastId].Cooldown);
Ability = hero.AbilityDict[hero.abilityCastId];
hero.AbilityDict[hero.abilityCastId].Method();
// Cancel casting the ability but don't fire SpellStop()
SkipSpellStop = true;
IssueImmediateOrder(hero.unit, "stop");
return;
}
hero.isCasting = true;
//hero.AbilityDict[hero.abilityCastId].Caster = hero; (this is already set)
if (GetSpellTargetUnit() != null) { hero.AbilityDict[hero.abilityCastId].Target = GetHero(GetSpellTargetUnit()); }
hero.AbilityDict[hero.abilityCastId].PointX = GetSpellTargetX();
hero.AbilityDict[hero.abilityCastId].PointY = GetSpellTargetY();
hero.AbilityDict[hero.abilityCastId].Angle = Atan2(hero.AbilityDict[hero.abilityCastId].PointY - hero.AbilityDict[hero.abilityCastId].CasterY,
hero.AbilityDict[hero.abilityCastId].PointX - hero.AbilityDict[hero.abilityCastId].CasterX);
// This timer allows the animation to play
TimerStart(CreateTimer(), 0.00f, false, () => {
TimerRemove(GetExpiredTimer());
if (hero.isCasting == false) { return; }
SetUnitTimeScale(hero.unit, hero.AbilityDict[hero.abilityCastId].AnimTimescale);
SetUnitAnimationByIndex(hero.unit, hero.AbilityDict[hero.abilityCastId].AnimIndex);
SpellCastingTimer(hero, hero.AbilityDict[hero.abilityCastId].CastingTime);
});
}
private static void SpellStop() {
if (SkipSpellStop) { SkipSpellStop = false; return; }
var hero = GetHero(GetTriggerUnit());
if (hero.AbilityDict[hero.abilityCastId].Option == Options.Instant) { return; }
if (hero.isCasting == false) { return; }
// Remove the ability timer so it doesn't run as well
TimerRemove(hero.abilityTimer);
// Reset casting state
SetUnitTimeScale(hero.unit, 1.0f);
hero.isCasting = false;
// If the hero is sliding they should return to their pre-cast facing angle
if (hero.isSliding) {
hero.slideCounter = 10; // 0.20 seconds of strafing time
SetUnitFacing(hero.unit, hero.slideAngle * RAD2DEG);
SetUnitAnimationByIndexDelay(hero.unit, hero.slideAnimation);
}
}
private static void SpellCastingTimer(Hero hero, float delay) {
TimerStart(hero.abilityTimer = CreateTimer(), delay, false, () => {
TimerRemove(hero.abilityTimer);
if (hero.isCasting == false) { return; }
hero.AbilityDict[hero.abilityCastId].CasterX = GetUnitX(hero.unit);
hero.AbilityDict[hero.abilityCastId].CasterY = GetUnitY(hero.unit);
hero.AbilityDict[hero.abilityCastId].Angle = Atan2(hero.AbilityDict[hero.abilityCastId].PointY - hero.AbilityDict[hero.abilityCastId].CasterY,
hero.AbilityDict[hero.abilityCastId].PointX - hero.AbilityDict[hero.abilityCastId].CasterX);
// Reset casting state
SetUnitTimeScale(hero.unit, 1.0f);
BlzStartUnitAbilityCooldown(hero.unit, hero.abilityCastId, hero.AbilityDict[hero.abilityCastId].Cooldown);
hero.isCasting = false;
// If the hero is sliding they should return to their pre-cast facing angle
if (hero.isSliding) {
hero.slideCounter = 20; // 0.40 seconds of strafing time
SetUnitFacing(hero.unit, hero.slideAngle * RAD2DEG);
SetUnitAnimationByIndexDelay(hero.unit, hero.slideAnimation);
}
// Call the ability method
Ability = hero.AbilityDict[hero.abilityCastId];
hero.AbilityDict[hero.abilityCastId].Method();
// Cancel casting the ability but don't fire SpellStop()
SkipSpellStop = true;
IssueImmediateOrder(hero.unit, "stop");
});
}
}