Moderator
M
Moderator
12th Nov 2011
Bribe: Thanks for making the changes, nice and unique spell here.
Approved.
Bribe: Thanks for making the changes, nice and unique spell here.
Approved.
//==============================================================================
// BINDING SHOT v1.3
// BY Ayanami
//==============================================================================
//==============================================================================
// REQUIREMENTS
//==============================================================================
// - JNGP
// - Alloc
// - SpellEffectEvent
// * RegisterPlayerUnitEvent
// * Table
// - Timer32
//==============================================================================
//==============================================================================
// IMPLEMENTATION
//==============================================================================
// 1) Copy the whole "Required Systems" Trigger folder
// 2) Copy the trigger "Binding Shot"
// 3) Copy the ability "Binding Shot"
// 4) Copy the unit "Binding Shot Dummy"
// 5) Go through the configuration section in "Binding Shot" trigger
//==============================================================================
library BindingShot uses Alloc, SpellEffectEvent, T32
//===========================================================================
// CONFIGURABLES
//===========================================================================
globals
private constant integer ABIL_ID = 'ABBS' // raw code of base ability
private constant integer DUMMY_ID = 'dBIN' // raw code of unit "Binding Shot Dummy"
private constant real ANIM_IMPACT = 0.5 // time taken for arrow to reach target
private constant real ANIM_BIND = 0.5 // time taken for enemies to be pulled back
private constant real ANIM_OFFSET = 200. // offset distance of pull location (relative to caster's location)
private constant real ANIM_HEIGHT = 50. // height of arrow
private constant real ANIM_LIGHT_HEIGHT = 50. // height of lightning attachment point
private constant string ANIM_LIGHTNING = "SPLK" // lightning type
private constant real ENUM_RADIUS = 176. // max collision size of a unit in your map.
private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type
private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type
endglobals
// bind area relative to target
private constant function GetArea takes integer level returns real
return 300.
endfunction
// damage dealt
private constant function GetDamage takes integer level returns real
return 80. * level + 40.
endfunction
// filter for allowed targets
private constant function GetFilter takes unit u, unit caster returns boolean
return /*
*/ not IsUnitType(u, UNIT_TYPE_DEAD) /* // target is alive
*/ and IsUnitEnemy(u, GetOwningPlayer(caster)) /* // target is an enemy of caster
*/ and not IsUnitType(u, UNIT_TYPE_STRUCTURE) // target is not a structure
endfunction
//===========================================================================
// END CONFIGURABLES
//===========================================================================
globals
private constant player NEUTRAL_PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
private group G = bj_lastCreatedGroup
endglobals
private struct Data extends array
implement Alloc
private unit u
private unit target
private unit dummy
private lightning l
private boolean b
private real dmg
private real dur
private real x
private real y
private method destroy takes nothing returns nothing
call RemoveUnit(this.dummy)
call DestroyLightning(this.l)
call this.stopPeriodic()
call this.deallocate()
endmethod
private method periodic takes nothing returns nothing
local real x
local real y
local real dx
local real dy
local real a
local real dist
local real offset
if not IsUnitType(this.target, UNIT_TYPE_DEAD) and GetUnitTypeId(this.target) != 0 then
set x = GetUnitX(this.dummy)
set y = GetUnitY(this.dummy)
if this.b then
set dx = this.x - x
set dy = this.y - y
set a = Atan2(dy, dx)
set dist = SquareRoot(dx * dx + dy * dy)
set offset = dist / this.dur * T32_PERIOD
call SetUnitX(this.target, GetUnitX(this.target) + offset * Cos(a))
call SetUnitY(this.target, GetUnitY(this.target) + offset * Sin(a))
else
set dx = GetUnitX(this.target) - x
set dy = GetUnitY(this.target) - y
set a = Atan2(dy, dx)
set dist = SquareRoot(dx * dx + dy * dy)
set offset = dist / this.dur * T32_PERIOD
call SetUnitFacing(this.dummy, a * bj_RADTODEG)
endif
call SetUnitX(this.dummy, x + offset * Cos(a))
call SetUnitY(this.dummy, y + offset * Sin(a))
call MoveLightningEx(this.l, true, GetUnitX(this.u), GetUnitY(this.u), GetUnitFlyHeight(this.u) + ANIM_LIGHT_HEIGHT, x, y, ANIM_HEIGHT + ANIM_LIGHT_HEIGHT)
set this.dur = this.dur - T32_PERIOD
if this.dur <= 0 then
if this.b then
call this.destroy()
else
set this.b = true
set this.dur = ANIM_BIND
call UnitDamageTarget(this.u, this.target, this.dmg, true, false, ATK, DMG, null)
endif
endif
else
call this.destroy()
endif
endmethod
implement T32x
private static method onCast takes nothing returns boolean
local thistype this
local unit u = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local integer level = GetUnitAbilityLevel(u, ABIL_ID)
local real a = GetUnitFacing(u) * bj_DEGTORAD
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real dx
local real dy
call GroupEnumUnitsInRange(G, GetUnitX(target), GetUnitY(target), GetArea(level) + ENUM_RADIUS, null)
loop
set target = FirstOfGroup(G)
exitwhen target == null
call GroupRemoveUnit(G, target)
if GetFilter(target, u) then
set this = thistype.allocate()
set this.u = u
set this.target = target
set dx = GetUnitX(target)
set dy = GetUnitY(target)
set this.dummy = CreateUnit(NEUTRAL_PASSIVE, DUMMY_ID, x, y, bj_RADTODEG * Atan2(dy - y, dx - x))
call SetUnitFlyHeight(this.dummy, ANIM_HEIGHT, 0)
set this.l = AddLightningEx(ANIM_LIGHTNING, true, x, y, GetUnitFlyHeight(this.u) + ANIM_LIGHT_HEIGHT, GetUnitX(this.dummy), GetUnitY(this.dummy), ANIM_HEIGHT + ANIM_LIGHT_HEIGHT)
set this.b = false
set this.dmg = GetDamage(level)
set this.dur = ANIM_IMPACT
set this.x = x + ANIM_OFFSET * Cos(a)
set this.y = y + ANIM_OFFSET * Sin(a)
call this.startPeriodic()
endif
endloop
set u = null
set target = null
return false
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABIL_ID, function thistype.onCast)
endmethod
endstruct
endlibrary