//
//
//
// *Pounce v1.0d
// by baassee
//
// A request by Zealon.
//
// *Requirements*
// None. Just the WE.
//
// *How to import*
//
// Read the how to import above the pounce init trigger.
//
// *Facts about the spell*
// The DOT is an object editor based spell, acidbomb.
// It gives us, slow and dps which is good and can if you want to
// also give us armor reduction.
//
// The spell code got it's own timer recycler, use it if you want to but remember to use
// it properly or it will bug. No this spell does not leak either timers or locations.
// The location is there to get the height of the location GetLocationZ which is needed
// for a proper parabola. But I use the native MoveLocation which moves the location
// so I only need one at all times and it doesnt leak.
// The timers are recycled so they will not leak either.
//
// The enumgroup will not leak either as it refreshes everytime you call the
// GroupEnumUnitsInRange native.
//
// And the unit is ordered to stop at the end of the spell. Why?
// Because if the unit is moving and you cast this spell, when it finishes
// the unit will move to its previous set movement point. Stopping the unit
// removes this.
//
// There are a few changeable functions below which I will explain a bit.
//
// *Credits*
// Zealon for the request
// baassee for the code
// Spec and moyack for the standard Parabola formula
//
// For vJASS users only
//
//globals
// private hashtable udg_PounceHash = InitHashtable()
// private timer array Timers
// private integer TimerN = 0
// private integer udg_TempInt = 0
// private attacktype udg_Pounce_AT = ATTACK_TYPE_NORMAL
// private damagetype udg_Pounce_DT = DAMAGE_TYPE_MAGIC
// private integer udg_Pounce_DummyType = 'stuf'
// private unit udg_Pounce_Dummy = CreateUnit(Player(15), udg_Pounce_DummyType, 0., 0., 0.)
// private integer udg_Pounce_ABILID = 'A000'
// private integer udg_Pounce_DummyABILID = 'A001'
// private location udg_PounceLoc = Location(0., 0.,)
// private real udg_Pounce_YMin
// private real udg_Pounce_YMax
// private real udg_Pounce_XMin
// private real udg_Pounce_XMax
//endglobals
//********CHANGEABLE FUNCTIONS**************
//obviously the total distance of the spell
function PounceDistance takes integer lvl returns real
return 300. + lvl * 100.
endfunction
//the height of the parabola
function PounceHeight takes integer lvl returns real
return 150. + lvl * 0
endfunction
//the hit damage of the spell aka when the unit reaches into a unit
// this is not the dps, dps is changeable in the object editor
function PounceHitDamage takes integer lvl returns real
return 40. * lvl
endfunction
//the speed the unit will move with, high values ~50 is not recommended
//0 speed and the spell will bug and the unit will not move
function PounceSpeed takes integer lvl returns real
return 18. + 4. * lvl
endfunction
//the aoe the spell has around the caster
function PounceAOE takes integer lvl returns real
return 85.
endfunction
//the special effect attached to the caster, like a trail or tail
//remember that in GUI the strings have one \ while in JASS it's two \\
function PounceEffect takes nothing returns string
return "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
endfunction
constant function PounceCollision takes nothing returns real
return 192.
endfunction
//an enum function
//basic units that cannot be targeted are
//dead
//structures
//magic immumne
//enemies
function PounceFilter takes unit u returns boolean
local unit c = LoadUnitHandle(udg_PounceHash, udg_TempInt, 0)
local boolean b = IsUnitEnemy(u, GetOwningPlayer(c)) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(u, UNIT_TYPE_DEAD)
set c = null
return b
endfunction
//***************END OF CONFIGURABLES************************
//standard parabola function
function PounceParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction
//simple timer recycler
//release the timer
function PounceRTimer takes timer t returns nothing
if t != null then
call PauseTimer(t)
set udg_Timers[udg_TimerN] = t
set udg_TimerN = udg_TimerN + 1
else
call BJDebugMsg("Tried to release a null timer")
endif
endfunction
//and get a timer
function PounceNTimer takes nothing returns timer
if udg_TimerN == 0 then
return CreateTimer()
endif
set udg_TimerN = udg_TimerN - 1
return udg_Timers[udg_TimerN]
endfunction
//the loop of the spell
function PounceLoop takes nothing returns nothing
local integer id = GetHandleId(GetExpiredTimer()) //get the handle's id
local real distx = LoadReal(udg_PounceHash, id, 6)//load some values
local real distance = LoadReal(udg_PounceHash, id, 1)
local real speed //all locals below are necessary if the spell is still on
local real aoe
local unit caster
local real cx
local real cy
local real nx
local real ny
local real height
local unit target
local real hitdmg
local boolean b = false
if distx < distance then //checks if we havent reached our goal
set caster = LoadUnitHandle(udg_PounceHash, id, 0) //loads the caster
set cx = GetUnitX(caster)
set cy = GetUnitY(caster)
set height = LoadReal(udg_PounceHash, id, 2) //loads other values
set speed = LoadReal(udg_PounceHash, id, 4)
set aoe = LoadReal(udg_PounceHash, id, 5)
set hitdmg = LoadReal(udg_PounceHash, id, 3)
set nx = cx + speed * LoadReal(udg_PounceHash, id, 7)
set ny = cy + speed * LoadReal(udg_PounceHash, id, 8)
//check that the next move coordinates are inside the map area
if udg_Pounce_XMin <= nx and nx <= udg_Pounce_XMax and udg_Pounce_YMin <= ny and ny <= udg_Pounce_YMax then
call SetUnitX(caster, nx)//sets the new coordinates aka moves the caster
call SetUnitY(caster, ny)
set distx = distx + speed
call SaveReal(udg_PounceHash, id, 6, distx)
call MoveLocation(udg_PounceLoc, nx, ny) //moves the location
call SetUnitFlyHeight(caster, PounceParabolaZ(height, distance, distx) + GetLocationZ(udg_PounceLoc), 0.) //just because im awesome
set udg_TempInt = id //here we need the global variable because locals cannot be transfered
call GroupEnumUnitsInRange(udg_EnumGroup, nx, ny, aoe + PounceCollision(), null)//enum
loop
set target = FirstOfGroup(udg_EnumGroup)
exitwhen b or target == null
call GroupRemoveUnit(udg_EnumGroup, target)
if IsUnitInRangeXY(target, nx, ny, aoe) and PounceFilter(target) then
call UnitDamageTarget(caster, target, hitdmg, false, false, udg_Pounce_AT, udg_Pounce_DT, null)
call SetUnitOwner(udg_Pounce_Dummy, GetOwningPlayer(caster), false) //changes dummy owner
call SetUnitX(udg_Pounce_Dummy, nx)//moves the dummy
call SetUnitY(udg_Pounce_Dummy, ny)
call SetUnitAbilityLevel(udg_Pounce_Dummy, udg_Pounce_DummyABILID, GetUnitAbilityLevel(caster, udg_Pounce_ABILID))
call IssueTargetOrder(udg_Pounce_Dummy, "acidbomb", target)//casts the spell
call SetUnitFlyHeight(caster, GetUnitDefaultFlyHeight(caster), 0.)
call UnitRemoveAbility(caster, 'Amrf')//removes the crowform
call PounceRTimer(GetExpiredTimer())//releases the timer
call DestroyEffect(LoadEffectHandle(udg_PounceHash, id, 9))//removes the trail
call PauseUnit(caster, false)//unpauses the unit
call IssueImmediateOrder(caster, "stop")
call FlushChildHashtable(udg_PounceHash, id)//flushes the childkeys
set b = true
endif
endloop
else
call SetUnitFlyHeight(caster, GetUnitDefaultFlyHeight(caster), 0.)
call UnitRemoveAbility(caster, 'Amrf')//fixes height and removes the crowform
call PounceRTimer(GetExpiredTimer())//releases timer
call DestroyEffect(LoadEffectHandle(udg_PounceHash, id, 9))//destroys effect
call PauseUnit(caster, false)//unpauses
call IssueImmediateOrder(caster, "stop")//to prevent a bug
call FlushChildHashtable(udg_PounceHash, id)//clear childkeys
endif
set caster = null//and nulls
set target = null
else //else if we have reached the total distance we
set caster = LoadUnitHandle(udg_PounceHash, id, 0)//load the caster
call SetUnitFlyHeight(caster, GetUnitDefaultFlyHeight(caster), 0.)
call UnitRemoveAbility(caster, 'Amrf')//fixes height and removes the crowform
call PounceRTimer(GetExpiredTimer())//releases timer
call DestroyEffect(LoadEffectHandle(udg_PounceHash, id, 9))//destroys effect
call PauseUnit(caster, false)//unpauses
call IssueImmediateOrder(caster, "stop")//to prevent a bug
call FlushChildHashtable(udg_PounceHash, id)//clear childkeys
set caster = null//nulls
endif
endfunction
//the normal cast trigger, it's awesome
function PounceCast takes nothing returns boolean
local timer t
local integer id //few locals needed
local integer lvl
local unit c
local real angle
if GetSpellAbilityId() == udg_Pounce_ABILID then //the ability check
set c = GetTriggerUnit()//gets the caster
set t = PounceNTimer() //gets a new timer
set id = GetHandleId(t) //gets the id of the timer
set lvl = GetUnitAbilityLevel(c, udg_Pounce_ABILID)
set angle = GetUnitFacing(c)
call SaveUnitHandle(udg_PounceHash, id, 0, c)//saves some values
call SaveReal(udg_PounceHash, id, 1, PounceDistance(lvl))
call SaveReal(udg_PounceHash, id, 2, PounceHeight(lvl))
call SaveReal(udg_PounceHash, id, 3, PounceHitDamage(lvl))
call SaveReal(udg_PounceHash, id, 4, PounceSpeed(lvl))
call SaveReal(udg_PounceHash, id, 5, PounceAOE(lvl))
call SaveReal(udg_PounceHash, id, 6, 0.)
call SaveReal(udg_PounceHash, id, 7, Cos(angle * bj_DEGTORAD))
call SaveReal(udg_PounceHash, id, 8, Sin(angle * bj_DEGTORAD))
call SaveEffectHandle(udg_PounceHash, id, 9, AddSpecialEffectTarget(PounceEffect(), c, "chest"))//adds the trail
call UnitAddAbility(c, 'Amrf')//adds crow from
call PauseUnit(c, true)//pauses the unit
call TimerStart(t, 0.03, true, function PounceLoop)//starts the loop
set c = null //and null
endif
return false
endfunction
//===========================================================================
//standard ini trigger
function InitTrig_Pounce takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function PounceCast))
//call UnitAddAbility(udg_Pounce_Dummy, udg_Pounce_DummyABILID)
//set udg_Pounce_YMin = GetRectMinY(bj_mapInitialPlayableArea)
//set udg_Pounce_YMax = GetRectMaxY(bj_mapInitialPlayableArea)
//set udg_Pounce_XMin = GetRectMinX(bj_mapInitialPlayableArea)
//set udg_Pounce_XMax = GetRectMaxX(bj_mapInitialPlayableArea)
endfunction