// **************************************************************************
// ** **
// ** Charge **
// ** ————————————— **
// ** **
// ** A simple Charge Spell **
// ** **
// ** By: Majin **
// **
// ** **
// **************************************************************************
library ChargeExec requires Knockback
struct ChargeLoop
private real ChargeTargetx
private real ChargeTargety
private real ChargeEndx
private real ChargeEndy
private real ChargeLocx
private real ChargeLocy
private real ChargeNextx
private real ChargeNexty
private unit ChargeTarget
private unit ChargeCaster
private real ChargeAngle
private real ChargeDistance
private effect ChargeEffect
private timer ChargeTimer
private boolean ChargeCond = false
private integer SpellLvl
//START OF CONFIGURATION METHODS
//With this method you can set the "acceleration rate" (Physicists Forgive me) of the charge.
//You can use any kind of numeric function (for example this.ChargeDistance * 2.00 will double
//The speed at every loop)
private method ChangeDistance takes nothing returns real
return this.ChargeDistance + 1.00
endmethod
//END OF CONFIGURATION METHODS
//START OF CUSTOMIZABLE METHODS
//This method sets the conditions when to activate the AlmostCharge method. In particular
//You may be interested in changing the distance at where the condition is true.
//In this Example it will be activated when the Caster is 16x times the Charge Speed Far away
//From the target
private method AlmostChargeCond takes nothing returns boolean
return ((GetDistance(this.ChargeLocx, this.ChargeLocy, this.ChargeEndx, this.ChargeEndy) < ( this.ChargeDistance * 16.00 )) and this.ChargeCond == false)
endmethod
//Actions to take when the Charge is almost completed. In this example the caster will play
//The slam animation (Being a Blademaster, it will jump in the air while attacking)
private method AlmostCharge takes nothing returns nothing
set this.ChargeCond = true
call SetUnitTimeScale( this.ChargeCaster, 2.00 )
call SetUnitAnimation( this.ChargeCaster, "slam" )
call QueueUnitAnimation( this.ChargeCaster, "stand")
endmethod
//Actions to take when the Caster reaches its target and the charge is completed.
//In this example the target unit will be stunned and you will see a Thunderclap effect on the ground
private method CompleteCharge takes nothing returns nothing
local effect tempEffect
local unit dummy
local real angle=GetAngle(this.ChargeLocx, this.ChargeLocy, this.ChargeEndx, this.ChargeEndy)
set this.ChargeLocx = this.ChargeNextx
set this.ChargeLocy = this.ChargeNexty
set this.ChargeNextx = PolarProjectionx(this.ChargeLocx, this.ChargeDistance, this.ChargeAngle)
set this.ChargeNexty = PolarProjectiony(this.ChargeLocy, this.ChargeDistance, this.ChargeAngle)
set tempEffect = AddSpecialEffect( WALKEFFECT, this.ChargeLocx, this.ChargeLocy )
call DestroyEffect( tempEffect )
call SetUnitX( this.ChargeCaster, this.ChargeEndx )
call SetUnitY( this.ChargeCaster, this.ChargeEndy )
set dummy = CreateUnit( GetOwningPlayer(this.ChargeCaster), DUMMYID, this.ChargeLocx, this.ChargeLocy, 0 )
call UnitAddAbility( dummy, DUMMYSPELLID )
call SetUnitAbilityLevel(dummy, DUMMYSPELLID, this.SpellLvl)
call IssueTargetOrder( dummy, SPELLORDERID, this.ChargeTarget )
call UnitApplyTimedLife( dummy, 'BTLF', 1.00)
set tempEffect = AddSpecialEffect( ENDINGEFFECT, this.ChargeLocx, this.ChargeLocy )
call DestroyEffect( tempEffect )
call UnitDamageTarget( this.ChargeCaster, this.ChargeTarget, CHARGEDAMAGE*this.SpellLvl, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS )
call PauseUnit( this.ChargeCaster, false )
//This is the Knockback effect, see the Knock Trigger for more customization options
call KnockbackEx(this.ChargeTarget, KNOCKDISTANCE*this.SpellLvl, angle, KNOCKDURATION, KnockTree(), KNOCKPLAYEFFECT, KNOCKEFFECT, KNOCKATTACH)
call IssueTargetOrder( this.ChargeCaster, "attack", this.ChargeTarget )
set tempEffect = null
set dummy = null
endmethod
//What to do during the charge, the unit is moved, an effect is placed on the ground and
//the charging speed is increased
private method ContinueCharge takes nothing returns nothing
local effect tempEffect
set tempEffect = AddSpecialEffect( WALKEFFECT, this.ChargeLocx, this.ChargeLocy )
call DestroyEffect( tempEffect )
call SetUnitX(this.ChargeCaster, this.ChargeNextx)
call SetUnitY(this.ChargeCaster, this.ChargeNexty)
call SetUnitFacing(this.ChargeCaster, bj_RADTODEG * GetAngle(this.ChargeNextx, this.ChargeNexty, this.ChargeTargetx, this.ChargeTargety))
set this.ChargeLocx = this.ChargeNextx
set this.ChargeLocy = this.ChargeNexty
set this.ChargeNextx = PolarProjectionx(this.ChargeLocx, this.ChargeDistance, this.ChargeAngle)
set this.ChargeNexty = PolarProjectiony(this.ChargeLocy, this.ChargeDistance, this.ChargeAngle)
if (this.ChargeDistance <= MAXSPEED) then
set this.ChargeDistance = this.ChangeDistance()
endif
set tempEffect = null
endmethod
//END OF CUSTOMIZABLE METHODS
//START OF OTHER METHODS
//This is the main method executed during the charge
public static method ChargeActions takes nothing returns nothing
local ChargeLoop l=GetTimerInt(GetExpiredTimer())
set l.ChargeTargetx = GetUnitX(l.ChargeTarget)
set l.ChargeTargety = GetUnitY(l.ChargeTarget)
set l.ChargeEndx = PolarProjectionx(l.ChargeTargetx, 100.00, GetAngle(l.ChargeTargetx, l.ChargeTargety, l.ChargeLocx, l.ChargeLocy))
set l.ChargeEndy = PolarProjectiony(l.ChargeTargety, 100.00, GetAngle(l.ChargeTargetx, l.ChargeTargety, l.ChargeLocx, l.ChargeLocy))
set l.ChargeAngle = GetAngle(l.ChargeLocx, l.ChargeLocy, l.ChargeEndx, l.ChargeEndy)
if ( l.AlmostChargeCond() ) then
//What to do when the caster is about to reach the target
call l.AlmostCharge()
endif
//If the Target gets too far away (by teleportation, for example) then stops the Charge
if ( GetDistance(l.ChargeLocx, l.ChargeLocy, l.ChargeEndx, l.ChargeEndy) >= MAXDISTANCE and (MAXDISTANCE != 0.00) ) then
call l.StopCharge()
endif
if ( l.ChargeConditions() ) then
//If the unit hasn't reached the target yet, then execute this
call l.ContinueCharge()
call TimerAttach(l.ChargeTimer,0.03,l,function ChargeLoop.ChargeActions)
else
if ( l.ChargeCompleted() ) then
//What to do if the charge is succesfully completed
call l.CompleteCharge()
endif
call l.StopCharge()
endif
endmethod
//Actions to take once the Charge is being stopped (either because it wasn't possible to complete
//the charge or because the caster reached its target)
private method StopCharge takes nothing returns nothing
set this.ChargeCond = false
call SetUnitPathing(this.ChargeCaster, true)
call PauseUnit(this.ChargeCaster, false)
call SetUnitAnimation(this.ChargeCaster, "stand")
call SetUnitTimeScale(this.ChargeCaster, 1.00)
call DestroyEffect(this.ChargeEffect)
call this.destroy()
endmethod
private method ChargeCompleted takes nothing returns boolean
if ((GetDistance(this.ChargeLocx, this.ChargeLocy, this.ChargeEndx, this.ChargeEndy) <= this.ChargeDistance*1.10) and IsPointWalkable(this.ChargeNextx, this.ChargeNexty)) then
if ((IsTerrainPathable(this.ChargeNextx, this.ChargeNexty, PATHING_TYPE_WALKABILITY) == false ) and ( (GetUnitState(this.ChargeTarget, UNIT_STATE_LIFE)<=0) == false )) then
if(((GetUnitState(this.ChargeCaster, UNIT_STATE_LIFE) <= 0) == false)) then
return true
endif
endif
endif
return false
endmethod
private method ChargeConditions takes nothing returns boolean
if ((GetDistance(this.ChargeLocx, this.ChargeLocy, this.ChargeEndx, this.ChargeEndy) > this.ChargeDistance*1.10) and IsPointWalkable(this.ChargeNextx, this.ChargeNexty)) then
if ((IsTerrainPathable(this.ChargeNextx, this.ChargeNexty, PATHING_TYPE_WALKABILITY) == false ) and ( (GetUnitState(this.ChargeTarget, UNIT_STATE_LIFE)<=0) == false )) then
if(((GetUnitState(this.ChargeCaster, UNIT_STATE_LIFE) <= 0) == false)) then
return true
endif
endif
endif
return false
endmethod
private method onDestroy takes nothing returns nothing
call ReleaseTimer(this.ChargeTimer)
set this.ChargeTarget = null
set this.ChargeCaster = null
set this.ChargeEffect = null
endmethod
static method create takes real pChargeTargetx, real pChargeTargety, real pChargeEndx, real pChargeEndy, real pChargeLocx, real pChargeLocy, real pChargeNextx, real pChargeNexty, unit pChargeTarget, unit pChargeCaster, real pChargeAngle, real pChargeDistance, effect pChargeEffect, timer pChargeTimer returns ChargeLoop
local ChargeLoop l = ChargeLoop.allocate()
set l.ChargeTargetx = pChargeTargetx
set l.ChargeTargety = pChargeTargety
set l.ChargeEndx = pChargeEndx
set l.ChargeEndy = pChargeEndy
set l.ChargeLocx = pChargeLocx
set l.ChargeLocy = pChargeLocy
set l.ChargeNextx = pChargeNextx
set l.ChargeNexty = pChargeNexty
set l.ChargeTarget = pChargeTarget
set l.ChargeCaster = pChargeCaster
set l.ChargeAngle = pChargeAngle
set l.ChargeDistance = pChargeDistance
set l.ChargeEffect = pChargeEffect
set l.ChargeTimer = pChargeTimer
set l.SpellLvl = GetUnitAbilityLevel(l.ChargeCaster, SPELLID)
return l
endmethod
//END OF OTHER METHODS
endstruct
endlibrary
//TRIGGER OF THE CHARGE SPELL
scope Charge initializer InitTrig
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == SPELLID
endfunction
private function CheckActions takes nothing returns nothing
local real ChargeLocx = GetUnitX(GetTriggerUnit())
local real ChargeLocy = GetUnitY(GetTriggerUnit())
local real ChargeEndx = GetUnitX(GetSpellTargetUnit())
local real ChargeEndy = GetUnitY(GetSpellTargetUnit())
if ( GetDistance(ChargeLocx, ChargeLocy, ChargeEndx, ChargeEndy) <= (MINDISTANCE) ) then
call DisplayTextToPlayer( GetOwningPlayer(GetTriggerUnit()), 0, 0, "|cffFFCC00Target is too close!|r" )
call PlaySound( "Sound\\Interface\\Error.wav" )
call IssueImmediateOrder( GetTriggerUnit(), "stop" )
endif
endfunction
private function InitActions takes nothing returns nothing
local timer ChargeTimer = NewTimer()
local effect ChargeEffect
local unit ChargeCaster = GetTriggerUnit()
local unit ChargeTarget = GetSpellTargetUnit()
local real ChargeDistance = STARTSPEED
local real ChargeLocx = GetUnitX(ChargeCaster)
local real ChargeLocy = GetUnitY(ChargeCaster)
local real ChargeTargetx = GetUnitX(ChargeTarget)
local real ChargeTargety = GetUnitY(ChargeTarget)
local real ChargeEndx = PolarProjectionx(ChargeTargetx, 100.00, GetAngle(ChargeTargetx, ChargeTargety, ChargeLocx, ChargeLocy))
local real ChargeEndy = PolarProjectiony(ChargeTargety, 100.00, GetAngle(ChargeTargetx, ChargeTargety, ChargeLocx, ChargeLocy))
local real ChargeAngle = GetAngle(ChargeLocx, ChargeLocy, ChargeEndx, ChargeEndy)
local real ChargeNextx = PolarProjectionx(ChargeLocx, ChargeDistance, ChargeAngle)
local real ChargeNexty = PolarProjectiony(ChargeLocy, ChargeDistance, ChargeAngle)
local ChargeLoop stru
set ChargeEffect = AddSpecialEffectTarget(ATTACHEDEFFECT, ChargeCaster, "chest" )
set stru = ChargeLoop.create(ChargeTargetx, ChargeTargety, ChargeEndx, ChargeEndy, ChargeLocx, ChargeLocy, ChargeNextx, ChargeNexty, ChargeTarget, ChargeCaster, ChargeAngle, ChargeDistance, ChargeEffect, ChargeTimer)
call SetUnitPathing(ChargeCaster, false)
call SetUnitTimeScale(ChargeCaster, 3)
call IssueImmediateOrder(ChargeCaster, "stop" )
call PauseUnit(ChargeCaster, true)
call SetUnitAnimationByIndex(ChargeCaster,6)
call TimerAttach(ChargeTimer,0,stru,function ChargeLoop.ChargeActions)
set ChargeTimer = null
set ChargeEffect = null
set ChargeCaster = null
set ChargeTarget = null
endfunction
private function AntiLeak takes nothing returns boolean
return true
endfunction
private function InitTrig takes nothing returns nothing
local trigger ChargeCheck = CreateTrigger()
local trigger ChargeInit = CreateTrigger()
local filterfunc f = Filter(function AntiLeak)
local integer i = 0
loop
exitwhen i == 16
call TriggerRegisterPlayerUnitEvent(ChargeCheck,Player(i),EVENT_PLAYER_UNIT_SPELL_CAST,f)
call TriggerRegisterPlayerUnitEvent(ChargeInit,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,f)
set i = i + 1
endloop
call TriggerAddCondition(ChargeCheck, Condition(function Conditions))
call TriggerAddAction(ChargeCheck, function CheckActions)
call TriggerAddCondition(ChargeInit, Condition(function Conditions))
call TriggerAddAction(ChargeInit, function InitActions)
set ChargeCheck = null
set ChargeInit = null
set f = null
endfunction
endscope