kingkingyyk3
Visitor (Welcome to the Jungle, Baby!)
- Reaction score
- 216
Bounce
Links : Damage, T32, Recycle, Event, (xe's link is unavailable because wc3c.net is downed )
-> Classical spells that can be made by this are Chain Frost(Lich's Ultimate in DotA), Chain Entangle, Paralysing Cask(Witch Doctor's first skill in DotA), and those chainy spells.
-> Demo map includes Chain Frost and triggered Moon Glaive.
-> (Moon Glaive)Don't ask me about the damage amount, there are other libraries to let you to get the actual damage dealt.
-> If you wanted to bypass the default unit picking mechanism(The library uses FirstOfGroup), just set .target by yourself in the onHit callback.
-> If you wanted to force the struct to be destroyed, just set .count = 0 and .target = null, it will be destroyed.
JASS:
Bounce v1.0.2
by kingking
Bouncing. Yeah, it is bouncing.
It makes your bouncing spells easier.
Requirements :
T32, Damage, Recycle or Damage, xefx, Event
How to implement?
1) Implement those required systems.
2) Copy this library into your map.
3) Enjoy!
Usage :
Make your struct extends Bounce
Example : private struct Data extends Bounce
Struct Members :
.startingUnit -> Starting unit.
.count -> Number of bounce.
.allowRepeatingUnits -> Allows/Disallows affected units to be picked again.
.callback -> When the missle is collided with unit, this will be called.
.filter -> Unit picking filter.
.collisionSize -> When range between missle and unit is under this value, bounce will occur.
.range -> Unit picking range.
.missleSpeed -> How fast the missle travelled.
.target -> Modify the target by your ownself.
.missleHeight -> Minimum height of missle.
.main -> Bouncing around which unit? (Bouncing around dummy is default)
.x -> X-axis of missle
.y -> Y-axis of missle
.z -> Z-axis of missle
Static methods :
.allocate() -> Returns an instance.
.create() -> Returns an instance. (If you have custom defined .create method.)
.register(trigger) return EvenReg -> Register trigger for all onHit event.
.getTriggering() -> Returns triggered instance.
Methods :
.startBouncing(model, scale) -> Starts bouncing.
Example for .callback :
method onHit takes unit whichUnit returns nothing
function onHit takes struct whichStruct, unit whichUnit returns nothing
Example for .filter :
method filterUnits takes unit whichUnit returns boolean
function filterUnits takes struct whichStruct, unit whichUnit returns boolean
(Picking living units are done by this library, you dont have to add it in your filter function.)
Note :
You dont have to call .destroy() on struct, it will be destroyed automatically.
JASS:
library Bounce requires Damage, T32, optional Recycle, optional GroupUtils, xefx, Event
function interface BounceCallback takes integer data, unit whichUnit returns nothing
function interface BounceUnitFilter takes integer data, unit whichUnit returns boolean
struct Bounce
// For event callbacks.
private static Event OnHit
private static thistype array OnHitData
//Array? Prevent recursion. =)
private static integer OnHitStackLevel = 0
//
private static conditionfunc condAllowRepeatingUnits
private static conditionfunc condDisallowRepeatingUnits
private static thistype d
integer count = 0
boolean allowRepeatingUnits = false
BounceCallback callback = 0
BounceUnitFilter filter = 0
real collisionSize = 16.
real range = .1
unit target
real missleHeight
unit main
private unit lastTarget
private xefx fx
private real speed
private real targetZ
private real lastTargetZ
readonly real x
readonly real y
private group damagedUnits
private conditionfunc cf
static method getTriggering takes nothing returns thistype
return thistype.OnHitData[thistype.OnHitStackLevel]
endmethod
private method onDestroy takes nothing returns nothing
call .stopPeriodic()
call .fx.destroy()
if not .allowRepeatingUnits then
static if LIBRARY_GroupUtils then
call ReleaseGroup(.damagedUnits)
else
call Group.release(.damagedUnits)
endif
endif
set .target = null
set .missleHeight = 0.
set .main = null
endmethod
private static method allowRepeating takes nothing returns boolean
local unit u = GetFilterUnit()
if GetWidgetLife(u) > .405 and thistype.d.filter.evaluate(thistype.d,u) and u != thistype.d.lastTarget then
set u = null
return true
endif
set u = null
return false
endmethod
private static method disallowRepeating takes nothing returns boolean
local unit u = GetFilterUnit()
if GetWidgetLife(u) > .405 and thistype.d.filter.evaluate(thistype.d,u) and u != thistype.d.lastTarget and not IsUnitInGroup(u,thistype.d.damagedUnits) then
set u = null
return true
endif
set u = null
return false
endmethod
private method periodic takes nothing returns nothing
local real dx
local real dy
local real tx
local real ty
local real angle
local real dist
local group g
if .target == null then
if .count > 0 then
static if LIBRARY_GroupUtils then
set g = NewGroup()
elseif LIBRARY_Recycle then
set g = Group.get()
endif
set thistype.d = this
call GroupEnumUnitsInRange(g,GetUnitX(.main),GetUnitY(.main),.range,.cf)
set .target = FirstOfGroup(g)
static if LIBRARY_GroupUtils then
call ReleaseGroup(g)
elseif LIBRARY_Recycle then
call Group.release(g)
endif
if .target == null then
//No more units in range.
call .destroy()
else
set .targetZ = GetUnitFlyHeight(.target)
endif
else
call .destroy()
//No more bounces left...
endif
else
set tx = GetUnitX(.target)
set ty = GetUnitY(.target)
set dx = tx - .x
set dy = ty - .y
set angle = Atan2(dy,dx)
set dist = dx * dx + dy * dy
set .x = .x + .speed * Cos(angle)
set .y = .y + .speed * Sin(angle)
set .fx.x = .x
set .fx.y = .y
set .fx.xyangle = angle
set dx = tx - GetUnitX(.lastTarget)
set dy = ty - GetUnitY(.lastTarget)
set .fx.z = .missleHeight + .lastTargetZ + (dist/(dx*dx+dy*dy)) * (.targetZ - .lastTargetZ)
//For flying units.
if IsUnitInRange(.fx.dummy,.target,.collisionSize) then
set .count = .count - 1
call .callback.evaluate(this,.target)//Too bad, jasshelper can't detect callback.exists in extended structs.
set thistype.OnHitStackLevel = thistype.OnHitStackLevel + 1
set thistype.OnHitData[thistype.OnHitStackLevel] = this
call thistype.OnHit.fire()
set thistype.OnHitStackLevel = thistype.OnHitStackLevel - 1
if not .allowRepeatingUnits then
call GroupAddUnit(.damagedUnits,.target)
endif
set .lastTarget = .target
set .lastTargetZ = .targetZ
set .target = null
endif
endif
endmethod
implement T32x
method operator missleSpeed= takes real mSpeed returns nothing
set .speed = mSpeed * T32_PERIOD
endmethod
method operator startingUnit= takes unit whichUnit returns nothing
set .lastTarget = whichUnit
endmethod
method operator z takes nothing returns real
return .fx.z
endmethod
method startBouncing takes string model, real scale returns nothing
set .x = GetUnitX(.lastTarget)
set .y = GetUnitY(.lastTarget)
set .lastTargetZ = GetUnitFlyHeight(.lastTarget)
set .fx = xefx.create(.x,.y,0.)
set .fx.z = .lastTargetZ
set .fx.fxpath = model
call SetUnitScale(.fx.dummy,scale,scale,0.)
if .main == null then
set .main = .fx.dummy
endif
if not .allowRepeatingUnits then
static if LIBRARY_GroupUtils then
set .damagedUnits = NewGroup()
elseif LIBRARY_Recycle then
set .damagedUnits = Group.get()
endif
set .cf = thistype.condDisallowRepeatingUnits
call GroupAddUnit(.damagedUnits,.lastTarget)
else
set .cf = thistype.condAllowRepeatingUnits
endif
call .startPeriodic()
endmethod
static method registerEvent takes trigger whichTrigger returns EventReg
return thistype.OnHit.register(whichTrigger)
endmethod
private static method onInit takes nothing returns nothing
set thistype.condAllowRepeatingUnits = Condition(function thistype.allowRepeating)
set thistype.condDisallowRepeatingUnits = Condition(function thistype.disallowRepeating)
set thistype.OnHit = Event.create()
static if not LIBRARY_GroupUtils and not LIBRARY_Recycle then
call BJDebugMsg("Bounce Error! Please implement either GroupUtils or Recycle for your map.")
endif
endmethod
endstruct
endlibrary
Links : Damage, T32, Recycle, Event, (xe's link is unavailable because wc3c.net is downed )
-> Classical spells that can be made by this are Chain Frost(Lich's Ultimate in DotA), Chain Entangle, Paralysing Cask(Witch Doctor's first skill in DotA), and those chainy spells.
-> Demo map includes Chain Frost and triggered Moon Glaive.
-> (Moon Glaive)Don't ask me about the damage amount, there are other libraries to let you to get the actual damage dealt.
-> If you wanted to bypass the default unit picking mechanism(The library uses FirstOfGroup), just set .target by yourself in the onHit callback.
-> If you wanted to force the struct to be destroyed, just set .count = 0 and .target = null, it will be destroyed.
JASS:
library ChainFrost requires GT, Bounce, DummyCaster
globals
private constant integer SPELL_ID = 039;A002039;
private constant string MISSLE_MODEL = "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"
private constant real MISSLE_SCALE = 1.
private constant real MISSLE_SPEED = 600.
private constant attacktype ATK_TYPE = ATTACK_TYPE_NORMAL
private constant damagetype DMG_TYPE = DAMAGE_TYPE_NORMAL
private constant integer FROST_NOVA = 039;A003039;
private constant string FROST_ORDER = "frostnova"
endglobals
private function Damage takes integer lv returns real
return 190. + (lv * 90.)
endfunction
private function BounceCount takes integer lv returns integer
return 7
endfunction
private function AoE takes integer lv returns real
return 600.
endfunction
private struct Data extends Bounce
unit caster
integer lv
player owner
real damage
private method onHit takes unit whichUnit returns nothing
if UnitAddAbility(DUMMY,FROST_NOVA) then
if IssueTargetOrder(DUMMY,FROST_ORDER,whichUnit) then
call UnitDamageTargetEx(.caster,whichUnit,.damage,false,false,ATK_TYPE,DMG_TYPE,null)
endif
call UnitRemoveAbility(DUMMY,FROST_NOVA)
endif
endmethod
//Pretty easy, huh?
private method filterUnits takes unit whichUnit returns boolean
return IsUnitEnemy(whichUnit,.owner)
endmethod
private static method act takes nothing returns boolean
local thistype this = thistype.allocate()
set .caster = GetTriggerUnit()
set .startingUnit = .caster
set .target = GetSpellTargetUnit()
set .lv = GetUnitAbilityLevel(.caster,SPELL_ID)
set .owner = GetOwningPlayer(.caster)
set .allowRepeatingUnits = true
set .count = BounceCount(.lv)
set .damage = Damage(.lv)
set .range = AoE(.lv)
set .collisionSize = 16.
set .missleSpeed = MISSLE_SPEED
set .callback = .onHit
set .filter = .filterUnits
set .missleHeight = 30.
set .main = .caster
call .startBouncing(MISSLE_MODEL,MISSLE_SCALE)
return false
endmethod
private static method onInit takes nothing returns nothing
call GT_AddStartsEffectAction(function thistype.act,SPELL_ID)
endmethod
endstruct
endlibrary