//------------------------------------------------------------------------------------\\
// Magnetic Field [v3] \\
// by kenny! \\
// Constructed using vJASS \\
// Requires NewGen WE & GTrigger \\
// Edited by SanKakU to have a visual boundary \\
// Constructed using cJASS \\
// Model by JetFangInferno \\
// hiveworkshop.com/forums/models-530/divinering-50484 \\
//------------------------------------------------------------------------------------\\
scope ShieldCK initializer onInit
globals
// Configurables:
private constant integer ABIL_ID='A07V'// Raw code of the Magnetic Field ability.
private constant integer DUMID='e00K'// Raw code of the dummy unit circle that shows boundary.
private constant integer DUMMY_ID='u00Q'// Raw code of the dummy unit used to destroy trees.
private constant real INTERVAL=0.03125// Used in the periodic timer to move units.
private constant real COLLISION=150.00// Area around the moving units in which trees will be destroyed.
private constant real DISTANCE=75.00 // DISTANCE for checking pathability. Should be at least 25.00 distance less than COLLISION!!!
private constant string CASTED_SFX= "Abilities\\Spells\\Undead\\Darksummoning\\DarkSummonTarget.mdl" // Special effect that is attached to the caster.
private constant string CASTED_POINT = "origin" // where the special effect is attached to the caster.
private constant boolean DESTROY_TREES = true // Whether or not to allow destroying trees.
private constant boolean ALLOW_PRELOAD = true // Whether or not to allow preloading of effects.
endglobals
private real Radius (integer lvl){return 330.00 + (110.00 * lvl)}//MEASURED AGAINST MODEL SIZE
//SHOULD BE 110.00 FOR EVERY 1.00 OF MODEL SIZE...
private real scalex (integer lvl){return 3.00 + (1.00 * lvl)}//WIDTH
private real scaley (integer lvl){return 3.00 + (1.00 * lvl)}//LENGTH
//NEEDS SOME MINOR ADJUSTMENT...
private real scalez (integer lvl){return 1.00 + (0.00 * lvl)}//HEIGHT
private real Duration (integer lvl){return 4.00 + (6.00 * lvl)}//CHANGE AS DESIRED
private real Move_dist (integer lvl){return 20.0 + (0.00 * lvl)}//WOULDN'T ADVISE TOUCH THIS ONE
//END OF CONFIGURABLES
public struct Data
unit dum=null
unit cast = null
effect sfx = null
real time = 0.00
integer lvl = 0
static Data array D
static item array Hidden
static integer Hidden_max = 0
static integer DT = 0
static rect Rect1 = null
static timer Timer = null
static group Group = null
static unit Tree_dummy = null
static item Item = null
static boolexpr Tree_filt = null
static boolexpr Unit_filt = null
static real Game_maxX = 0.00
static real Game_minX = 0.00
static real Game_maxY = 0.00
static real Game_minY = 0.00
static real Max_range = 10.00
static method hide takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set .Hidden[.Hidden_max] = GetEnumItem()
call SetItemVisible(.Hidden[.Hidden_max],false)
set .Hidden_max = .Hidden_max + 1
endif
endmethod
static method pathability takes real x1, real y1 returns boolean
local real x2 = 0.00
local real y2 = 0.00
call SetRect(.Rect1,0.00,0.00,128.00,128.00)
call MoveRectTo(.Rect1,x1,y1)
call EnumItemsInRect(.Rect1,null,function Data.hide)
call SetItemPosition(.Item,x1,y1)
set x2 = GetItemX(.Item)
set y2 = GetItemY(.Item)
call SetItemVisible(.Item,false)
loop
exitwhen .Hidden_max <= 0
set .Hidden_max = .Hidden_max - 1
call SetItemVisible(.Hidden[.Hidden_max],true)
set .Hidden[.Hidden_max] = null
endloop
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) < .Max_range * .Max_range
endmethod
static method safex takes real x returns real
if x < .Game_minX then
return .Game_minX
elseif x > .Game_maxX then
return .Game_maxX
endif
return x
endmethod
static method safey takes real y returns real
if y < .Game_minY then
return .Game_minY
elseif y > .Game_maxY then
return .Game_maxY
endif
return y
endmethod
static method destroyenumtrees takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endmethod
static method treefilt takes nothing returns boolean
local destructable dest = GetFilterDestructable()
local boolean result = false
if GetDestructableLife(dest) > 0.405 then
call ShowUnit(.Tree_dummy,true)
call SetUnitX(.Tree_dummy,GetWidgetX(dest))
call SetUnitY(.Tree_dummy,GetWidgetY(dest))
set result = IssueTargetOrder(.Tree_dummy,"harvest",dest)
call IssueImmediateOrder(.Tree_dummy,"stop")
call ShowUnit(.Tree_dummy,false)
set dest = null
return result
endif
set dest = null
return result
endmethod
static method unitfilt takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > 0.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false
endmethod
private method onDestroy takes nothing returns nothing
call DestroyEffect(.sfx)
RemoveUnit(.dum)
set .sfx = null
set .cast = null
endmethod
static method update takes nothing returns nothing
local Data d = 0
local integer i = 1
local unit u = null
local real castx = 0.00
local real casty = 0.00
local real angle = 0.00
local real sin = 0.00
local real cos = 0.00
local real ux = 0.00
local real uy = 0.00
loop
exitwhen i > .DT
set d = .D[i]
set castx = GetUnitX(d.cast)
set casty = GetUnitY(d.cast)
call SetUnitPosition(d.dum,castx,casty)
if d.time >= Duration(d.lvl) or GetWidgetLife(d.cast) < 0.405 then
call d.destroy()
set .D[i] = .D[.DT]
set .DT = .DT - 1
set i = i - 1
else
call GroupEnumUnitsInRange(.Group,castx,casty,Radius(d.lvl),.Unit_filt)
call GroupRemoveUnit(.Group,d.cast)
loop
set u = FirstOfGroup(.Group)
exitwhen u == null
call GroupRemoveUnit(.Group,u)
set ux = GetUnitX(u)
set uy = GetUnitY(u)
set angle = Atan2((uy - casty),(ux - castx))
set sin = Sin(angle)
set cos = Cos(angle)
if .pathability(ux + DISTANCE * cos,uy + DISTANCE * sin) then
set ux = .safex(ux + Move_dist(d.lvl) * cos)
set uy = .safey(uy + Move_dist(d.lvl) * sin)
call SetUnitPosition(u,ux,uy)
if DESTROY_TREES then
call SetRect(.Rect1,ux - COLLISION,uy - COLLISION,ux + COLLISION,uy + COLLISION)
call EnumDestructablesInRect(.Rect1,.Tree_filt,function Data.destroyenumtrees)
endif
endif
endloop
set d.time = d.time + INTERVAL
endif
set i = i + 1
endloop
if .DT <= 0 then
call PauseTimer(.Timer)
set .DT = 0
endif
set u = null
endmethod
static method actions takes nothing returns boolean
local Data d = Data.create()
set d.cast = GetTriggerUnit()
set d.lvl = GetUnitAbilityLevel(d.cast,ABIL_ID)
set d.sfx = AddSpecialEffectTarget(CASTED_SFX,d.cast,CASTED_POINT)
set d.dum = CreateUnit(GetOwningPlayer(d.cast),DUMID,GetUnitX(d.cast),GetUnitY(d.cast),GetUnitFacing(d.cast))
SetUnitScale(d.dum,scalex(d.lvl),scaley(d.lvl),scalez(d.lvl))
set .DT = .DT + 1
set .D[.DT] = d
if .DT == 1 then
call TimerStart(.Timer,INTERVAL,true,function Data.update)
endif
return false
endmethod
static method onInit takes nothing returns nothing
set .Timer = CreateTimer()
set .Group = CreateGroup()
set .Rect1 = Rect(0.00,0.00,1.00,1.00)
set .Tree_filt = Filter(function Data.treefilt)
set .Unit_filt = Filter(function Data.unitfilt)
set .Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea) - 64.00
set .Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea) - 64.00
set .Game_minX = GetRectMinX(bj_mapInitialPlayableArea) + 64.00
set .Game_minY = GetRectMinY(bj_mapInitialPlayableArea) + 64.00
// Register event.
call GT_AddStartsEffectAction(function Data.actions,ABIL_ID)
set .Tree_dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),DUMMY_ID,400,-400,0.00)
call SetUnitPathing(.Tree_dummy,false)
call ShowUnit(.Tree_dummy,false)
set .Item = CreateItem('ciri',400,-400)
call SetItemVisible(.Item,false)
if ALLOW_PRELOAD then
call DestroyEffect(AddSpecialEffect(CASTED_SFX,400,-400))
endif
endmethod
endstruct
endscope