//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//All functions are made by OrkOfMordor aka Hanky aka MDZ-OrkOfMordor! //
// //
// Thanx to Vexorian for his JassNewGenPack (download the modificated editor at: www.wc3campaigns.net)! //
// //
// This Spellpack uses: //
// - JassNewGenPack //
// - some Systems from OrkOfMordor aka Hanky aka MDZ-OrkOfMordor //
// //
// To use this spellpack you need: //
// - JassNewGenPack //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//! textmacro CostumMotion takes type,run,end,periodic
static timer loopExe=CreateTimer()
static integer size =0
static $type$ array runStruct
boolean active
boolean paused
static method loopRun takes nothing returns nothing
local integer index=0
loop
exitwhen index==$type$.size
if not $type$.runStruct[index].paused then
if $type$.runStruct[index].active then
call $type$.runStruct[index].$run$()
set index=index+1
else
call $type$.runStruct[index].$end$()
set $type$.size=$type$.size-1
set $type$.runStruct[index]=$type$.runStruct[$type$.size]
endif
else
set index=index+1
endif
endloop
if $type$.size==0 then
call PauseTimer($type$.loopExe)
endif
endmethod
static method addMotion takes $type$ data returns integer
if $type$.size==0 then
call TimerStart($type$.loopExe,$periodic$,true,function $type$.loopRun)
endif
set $type$.runStruct[$type$.size] =data
set $type$.runStruct[$type$.size].active=true
set $type$.runStruct[$type$.size].paused=false
set $type$.size =$type$.size+1
return $type$.size
endmethod
//! endtextmacro
//================================================================================================
//Hashtable Index System
//================================================================================================
library HIS
globals
//Config Part
private constant integer size=8190
private constant integer pos =0
//Hashtable Var
private hashtable tempcache=InitHashtable()
//Important SystemVars
private integer array inUse[size]
private integer array last [size]
private integer indexsize=0
private integer lastsize =0
endglobals
//System Code
function AddHandleIndex takes handle h returns nothing
local integer id=GetHandleId(h)
local integer qi
if HaveSavedInteger(tempcache,id,pos) then
set qi=LoadInteger(tempcache,id,pos)
set inUse[qi]=inUse[qi]+1
elseif lastsize>0 then
set lastsize =lastsize-1
set inUse[last[lastsize]]=1
call SaveInteger(tempcache,id,pos,last[lastsize])
else
set inUse[indexsize]=1
call SaveInteger(tempcache,id,pos,indexsize)
set indexsize=indexsize+1
endif
endfunction
function GetHandleIndex takes handle h returns integer
debug if not HaveSavedInteger(tempcache,GetHandleId(h),pos) then
debug call BJDebugMsg("Error: No index attached to handle [#100]")
debug endif
return LoadInteger(tempcache,GetHandleId(h),pos)
endfunction
function ClearHandleIndex takes handle h returns nothing
local integer id=GetHandleId(h)
local integer qi=LoadInteger(tempcache,id,pos)
debug if HaveSavedInteger(tempcache,id,pos) then
set inUse[qi]=inUse[qi]-1
if inUse[qi]==0 then
set last[lastsize]=qi
set lastsize =lastsize+1
call FlushChildHashtable(tempcache,id)
endif
debug else
debug call BJDebugMsg("Error: No index attached to handle [#101]")
debug endif
endfunction
endlibrary
library MainFunctions initializer init
globals
constant integer maxIndex =8190 //The maximal array index
constant integer minIndex =0x100000//The start index
private constant integer getWalkable_id='sehr'
private constant integer flyHack ='Amrf'
public group loopG =null
public boolexpr filter =null
private item getWalkable=null
private location loc =null
private rect check =null
endglobals
function UnitAddFly takes unit u returns nothing
call UnitAddAbility(u,flyHack)
call UnitRemoveAbility(u,flyHack)
endfunction
//Same as AngleBetweenPoints just with coords.
function A2PXY takes real x,real y,real xt,real yt returns real
return ModuloReal(bj_RADTODEG*Atan2(yt-y,xt-x),360.)
endfunction
//Same as DistanceBetweenPoints just with coords.
function D2PXY takes real x,real y,real xt,real yt returns real
local real dx=xt-x
local real dy=yt-y
return SquareRoot(dx*dx+dy*dy)
endfunction
//Prove if point is walkable.
function IsPointWalkable takes real x,real y returns boolean
call SetItemPosition(getWalkable,x,y)
call SetItemVisible(getWalkable,false)
return GetItemX(getWalkable)==x and GetItemY(getWalkable)==y
endfunction
//DEBUG boolxpr leak
private function AntiLeak takes nothing returns boolean
return true
endfunction
//Get Units in Rect with global group. Just use ClearGroup and not Destroy.
function GetUnitsInRect takes real minX,real minY,real maxX,real maxY returns group
call SetRect(check,minX,minY,maxX,maxY)
call GroupEnumUnitsInRect(loopG,check,filter)
return loopG
endfunction
//Get Units in Range with global group. Just use ClearGroup and not Destroy.
function GetUnitsInRange takes real radius,real x,real y returns group
call GroupEnumUnitsInRange(loopG,x,y,radius,filter)
return loopG
endfunction
//Get Z of x/y
function GetZ takes real x,real y returns real
call MoveLocation(loc,x,y)
return GetLocationZ(loc)
endfunction
//The standart conditions for a spell
constant function IsUnitNotImmun takes unit c,unit u returns boolean
return c!=u and not IsUnitType(u,UNIT_TYPE_STRUCTURE) and not IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE) and IsUnitEnemy(u, GetOwningPlayer(c)) and GetUnitState(u,UNIT_STATE_LIFE) > 0.00
endfunction
//Init the globals
private function init takes nothing returns nothing
set getWalkable=CreateItem(getWalkable_id,0,0)
set loc =Location(0,0)
set loopG =CreateGroup()
set check =Rect(0,0,0,0)
set filter =Filter(function AntiLeak)
call SetItemVisible(getWalkable,false)
endfunction
endlibrary
//================================================================================================
//Timer - Timer Recycler
//================================================================================================
//This is a standart timer recycler. It's so fast like TimerUtils and some benchmark tests
//showed that this system seems to be sometimes faster than both TimerUtil versions.
//But try it out yourself.
library TimerRecycler requires MainFunctions,HIS
globals
private constant integer pos =0
private hashtable hs =InitHashtable()
private integer lastsize =0
private timer array last[maxIndex]
endglobals
//! textmacro NextTimer takes name,type,func
function GetNextTimer$name$ takes $type$ dat returns timer
local integer index
local timer temp
if lastsize>0 then
set lastsize=lastsize-1
set temp =last[lastsize]
else
set temp =CreateTimer()
endif
call AddHandleIndex(temp)
call Save$func$(hs,GetHandleIndex(temp),pos,dat)
return temp
endfunction
//! endtextmacro
//! runtextmacro NextTimer("Int","integer","Integer")
//! runtextmacro NextTimer("Agent","agent","AgentHandle")
//! runtextmacro NextTimer("TextTag","texttag","TextTagHandle")
//! runtextmacro NextTimer("Lightning","lightning","LightningHandle")
//! textmacro GetType takes name,type,func
function GetTimerData$name$ takes timer t returns $type$
return Load$func$(hs,GetHandleIndex(t),pos)
endfunction
//! endtextmacro
//! runtextmacro GetType("Int","integer","Integer")
//! runtextmacro GetType("Unit","unit","UnitHandle")
//! runtextmacro GetType("Effect","effect","EffectHandle")
//! runtextmacro GetType("Lightning","lightning","LightningHandle")
//! runtextmacro GetType("TextTag","texttag","TextTagHandle")
function RecycleTimer takes timer t returns nothing
local integer index=GetHandleIndex(t)
call PauseTimer(t)
call ClearHandleIndex(t)
set last[lastsize]=t
set lastsize =lastsize+1
endfunction
endlibrary
//================================================================================================
//Group - Group Recycler
//================================================================================================
//A standart group recycler.
library GroupRecycler requires MainFunctions,HIS
globals
private integer max =0
private integer cmax =0
private group array rGroup
private integer array rInt[maxIndex]
endglobals
function GetNextGroup takes nothing returns group
set cmax=cmax+1
if max<cmax then
set rGroup[cmax]=CreateGroup()
set max =cmax
endif
call AddHandleIndex(rGroup[cmax])
set rInt[GetHandleIndex(rGroup[cmax])]=cmax
return rGroup[cmax]
endfunction
function RecycleGroup takes group g returns nothing
local integer index=GetHandleIndex(g)
call ClearHandleIndex(g)
set rGroup[rInt[index]] =rGroup[cmax]
set rInt[GetHandleIndex(rGroup[cmax])]=rInt[index]
set rGroup[cmax] =g
set cmax=cmax-1
endfunction
endlibrary
//================================================================================================
//Timed - Handle Destroy
//================================================================================================
//Some small useful functions.
library TimedHandleDead requires MainFunctions,TimerRecycler
function U2Death takes nothing returns nothing
local timer t = GetExpiredTimer()
call RemoveUnit(GetTimerDataUnit(t))
call RecycleTimer(t)
set t=null
endfunction
function U2Null takes unit u,real duration returns nothing
local timer t = GetNextTimerAgent(u)
call TimerStart(t,duration,false,function U2Death)
set t = null
endfunction
function E2Death takes nothing returns nothing
local timer t = GetExpiredTimer()
call DestroyEffect(GetTimerDataEffect(t))
call RecycleTimer(t)
set t=null
endfunction
function E2Null takes effect e,real duration returns nothing
local timer t = GetNextTimerAgent(e)
call TimerStart(t,duration,false,function E2Death)
set t = null
endfunction
function L2Death takes nothing returns nothing
local timer t = GetExpiredTimer()
call DestroyLightning(GetTimerDataLightning(t))
call RecycleTimer(t)
set t=null
endfunction
function L2Null takes lightning l,real duration returns nothing
local timer t = GetNextTimerLightning(l)
call TimerStart(t,duration,false,function L2Death)
set t = null
endfunction
function TT2Death takes nothing returns nothing
local timer t = GetExpiredTimer()
call DestroyTextTag(GetTimerDataTextTag(t))
call RecycleTimer(t)
set t=null
endfunction
function TT2Null takes texttag tt,real duration returns nothing
local timer t = GetNextTimerTextTag(tt)
call TimerStart(t,duration,false,function L2Death)
set t = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
// ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
// Û Û
// Û Û
// ßßßßßÛ Ûßßßßß
// Û Û
// Û Û ÜÜÜÜÜÜ ÜÜÜÜÜÜÜ
// Û Û Û Û Û Û
// Û Û Û Ü Û Û Ûßßßßßß
// Û Û Û ÛÛ Û Û Û
// Û Û Û Û Û Û Û Û ÜÜÜ
// Û Û Û Û Û Û Û Û Û Û
// Û Û Û ßßß Û Û ÛÜÜÛ Û
// Û Û Û Û Û Û
// ßßßß ßßßßßßßß ßßßßßßß
// ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
// ³ Clan TDG @ Azeroth ¸ ³
// ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
// Screen Solution: 1280x1024 Visit www.jx3.net/TDG!
// ++++++++++++++++++++++++++++++++++++++++++ INFO ++++++++++++++++++++++++++++++++++++++++
// Type........................................ : ......................................Spell
// Langueage................................... : ......................................vJass
// Coder....................................... : ......................................Hanky
// MUI......................................... : ........................................Yes
// ++++++++++++++++++++++++++++++++++++++++++ NOTES ++++++++++++++++++++++++++++++++++++++++
// Thanks for the JassGenNewPack: .............pipedream
// .............xttocs
// .............Pitzermike
// .............Vexorian
// .............MindWorx
// .............Scio
// .............Starcraftfreak
// .............FyreDaug
// .............KDEWolf
// Greetz fly out to: NgO . BuranX . JonNny . Darkt3mpl3r . WaRadius . Fireeye
// CBS . WC3C . HIVE . Toadcop . Paladon . Eccho
//
// Enjoy!
scope MagicalTrap initializer init
globals
// Standard Spell Id's
private constant integer SpellId = 'A000' //The ability id of the spell.
private constant integer EffectId = 'A001' //The ability id of the effect.
private constant integer DummyId = 'e000' //The unit id of the dummy.
private constant integer AttachKey = 22 //Don't change it. Its the attach key.
private constant real interval = 0.03 //Periodic time of the motion
private rect GameArea = null //The maximal gamearea.
private group GravityGroup = null //Global Group its for DEBUG and MUIness
private integer array structIndex[maxIndex] //This attach the struct to an unit
// End Effect
// This animation is when the wards get destroyed.
private constant real BlowAwayXYZ = 200. //The get distance. All units who are in the near get blowed away.
private constant real BlowAwayRadius = 300. //The distance the units get blowed away.
private constant real BlowAwayMaxZ = 300. //The maximal fly z.
private constant real BlowAwaySpeed = 10. //The speed of the units who are blowed away.
private constant real BlowAwayBackRate = 700. //How long it will take that the units are at the default z.
private constant string BlowAwayDamageGFXPa = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl" //This is the model the units get after they blowed away.
private constant string BlowAwayGFXPath = "Objects\\Spawnmodels\\Undead\\UDeathMedium\\UDeath.mdl" //This is the model which appear after the wards are destroyed.
// Ward Effect
// This is the standart spell animation when the gravity field moving up and down.
private constant real WardZ = 120. //The default z of the dummy unit.
private constant integer WardExperationType = 'Bhwd' //The experation timer type of the unit.
private constant string Animation_LightGFX = "DRAM" //The lightning type of the ligthning.
private constant integer Animation_XtraGFXS = 1 //The size of the dummy mdl.
private constant integer Animation_XtraDummy= 'e001' //The dummy unit id of the gravity field.
private constant real Animation_XtraFadeZ = 250. //The fade high of the effects. (This value should be always smaller then Animation_MaxZ)
private constant real Animation_MaxZ = 400. //The maximal z for the spell.
private constant real Animation_BackRateZ = 600. //How long it will take that the units are at the default z.
private constant real EffectSpeed = 5. //The z speed of the field.
private constant real GravityNewSpeed = 10. //The z speed of a victim if its new.
private constant real GravityLeaveSpeed = 10. //The z speed of a victim if it leave.
private constant string DamageGFXPath = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl" //The model for the damage the unit get if it fall down.
private constant string DamageGFXAttach = "origin"//The attach point for the damage model.
// Ward Constants
private constant integer WardId = 'n000' //The unit id of the ward.
private constant integer WardAmount = 3 //This is the amount of wards which will spawned.
private constant real WardTargetDeviation = 30. //This value makes the ward creation more random. If you maybe have setted to many wards this could cause error's but you can easily fix it with lowering this value.
// Summon Animation
// This animation when the wards slowly fall down to there positions.
private constant real Animation_Duration = 1.5 //This is the duration how long it will take that the wards fall down.
private constant real Animation_SGFXSize = 1. //The size of the dummy ward.
private constant string Animation_SGFXPath = "Units\\Creeps\\MonsterLure\\MonsterLure.mdl" //The model of the dummy ward.
private constant string Animation_SGFXAtt = "origin" //The attach point for model.
// Start Animation Constants
// This is the animation which shoot the magic missile in the sky.
private constant string Animation_GFXPath = "Abilities\\Spells\\Undead\\DevourMagic\\DevourMagicBirthMissile.mdl" //The model of the dummy which will be shooted in the sky.
private constant string Animation_GFXAtt = "origin" //The attach point for model.
private constant real Animation_GFXSize = 2. //The size of the model.
private constant real Animation_GFXSpeed = 10. //The speed of the dummy.
private constant real Animation_FlyHeight = 500. //The maximal fly height of the dummy
endglobals
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Level Constants $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//The damage units get who are blowed away by the ward explosion
private constant function BlowAwayDamage takes integer lvl returns real
return lvl*60.
endfunction
//The damage units get per every meter z they fall
private constant function Damage takes integer lvl returns real
return lvl*0.25
endfunction
//The movespeed which will be decreased
private constant function MoveSpeedDecrease takes integer lvl returns real
return 40. //The value is in percent
endfunction
//The duration how long the wards will be there
private constant function WardDuration takes integer lvl returns real
return 60. //The value is in seconds
endfunction
//The distance of the ward to the selected target point. You also can call it the radius for the spell.
private constant function WardTargetDistance takes integer lvl returns real
return 300.
endfunction
//The condition if the victim gonna be affected by the plane
private constant function EnumUnitPlaneFilter takes unit caster, unit victim returns boolean
return caster!=victim and IsUnitType(victim,UNIT_TYPE_STRUCTURE)==false and IsUnitType(victim,UNIT_TYPE_MAGIC_IMMUNE)==false and IsUnitEnemy(victim, GetOwningPlayer(caster)) and GetUnitState(victim,UNIT_STATE_LIFE) > 0.00
endfunction
//The condition if the victim gonna be affected by the explosion
private constant function EnumUnitExplosionFilter takes unit caster, unit victim returns boolean
return caster!=victim and IsUnitType(victim,UNIT_TYPE_STRUCTURE)==false and IsUnitType(victim,UNIT_TYPE_MAGIC_IMMUNE)==false and IsUnitEnemy(victim, GetOwningPlayer(caster)) and GetUnitState(victim,UNIT_STATE_LIFE) > 0.00
endfunction
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Spell Stuff $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//The ward datas.
private struct WardDatas
unit ward
real x
real y
real z
real mx
real my
real mz
boolean animation
method onDestroy takes nothing returns nothing
call KillUnit(.ward)
call U2Null(.ward,1.)
set .ward=null
endmethod
endstruct
//The unit datas.
private struct UnitDatas
real z
real dmg
real distance
real tempdistance
real x
real y
real mx
real my
boolean leave
boolean falling
boolean new
endstruct
// The end effect
private struct WardEnd
unit caster
group flyaway
//Move all units away who were in the explosion
method motion takes nothing returns nothing
local group check=MainFunctions_loopG
local integer id
local real x
local real y
local real z
local real cz
local UnitDatas ud
local unit a
call GroupAddGroup(.flyaway,check)
loop
set a=FirstOfGroup(check)
exitwhen a==null
call GroupRemoveUnit(check,a)
set id=GetHandleIndex(a)
set ud=structIndex[id]
set x=ud.x+ud.mx
set y=ud.y+ud.my
if IsPointWalkable(x,y) and RectContainsCoords(GameArea,x,y) then
set ud.x=x
set ud.y=y
endif
set ud.tempdistance=ud.tempdistance+BlowAwaySpeed
set cz =GetZ(ud.x,ud.y)
set z =Sin((ud.tempdistance/ud.distance)*3.14159)*BlowAwayMaxZ+ud.z-cz
call SetUnitPosition(a,ud.x,ud.y)
call SetUnitFlyHeight(a,z,0.)
if z<=cz then
call GroupRemoveUnit(.flyaway,a)
call SetUnitPathing(a,true)
call SetUnitFlyHeight(a,GetUnitDefaultFlyHeight(a),BlowAwayBackRate)
call DestroyEffect(AddSpecialEffect(BlowAwayDamageGFXPa,ud.x,ud.y))
call UnitDamageTarget(.caster,a,ud.dmg,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
if IsUnitInGroup(a,GravityGroup) then
call GroupRemoveUnit(GravityGroup,a)
endif
call ClearHandleIndex(a)
set structIndex[id]=0
call ud.destroy()
endif
endloop
if FirstOfGroup(.flyaway)==null then
set .active=false
endif
set check=null
endmethod
method endmotion takes nothing returns nothing
call RecycleGroup(.flyaway)
set .flyaway=null
set .caster =null
call .destroy()
endmethod
//! runtextmacro CostumMotion("WardEnd","motion","endmotion","interval")
endstruct
// The ward effect
private struct WardEffect
unit caster
group gravity
WardDatas array wd[WardAmount]
lightning array light[WardAmount]
unit array dummy[WardAmount]
real currentZ
real maxX
real maxY
real minX
real minY
real mfade
real fade
boolean explosion
method WardExplosion takes nothing returns nothing
local integer i =0
local WardEnd we =WardEnd.create()
local integer lvl=GetUnitAbilityLevel(.caster,SpellId)
local integer id
local real angle
local real z
local group check
local unit a
local UnitDatas ud
set .currentZ =0.
set .explosion=true
set we.caster =.caster
set we.flyaway=GetNextGroup()
loop
exitwhen i==WardAmount
// Ward Explosion Effect
set check=GetUnitsInRange(BlowAwayXYZ,.wd[i].x,.wd[i].y)
loop
set a=FirstOfGroup(check)
exitwhen a==null
call GroupRemoveUnit(check,a)
if EnumUnitExplosionFilter(.caster,a) then
set id=GetHandleIndex(a)
if IsUnitInGroup(a,.gravity) then
set ud=structIndex[id]
set z=ud.z
else
set z=GetUnitDefaultFlyHeight(a)
endif
if z<=BlowAwayXYZ then
if IsUnitInGroup(a,.gravity) then
call GroupRemoveUnit(.gravity,a)
call UnitRemoveAbility(a,EffectId)
else
call AddHandleIndex(a)
set id=GetHandleIndex(a)
set ud=UnitDatas.create()
call GroupAddUnit(GravityGroup,a)
endif
call GroupAddUnit(we.flyaway,a)
set ud.distance =BlowAwayRadius+z
set ud.tempdistance=Asin(ud.z/BlowAwayMaxZ/3.14159)*ud.distance
set ud.x =GetUnitX(a)
set ud.y =GetUnitY(a)
set ud.z =GetZ(.wd[i].x,.wd[i].y)
set angle =Atan2(ud.y-.wd[i].y,ud.x-.wd[i].x)
set ud.mx =BlowAwaySpeed*Cos(angle)
set ud.my =BlowAwaySpeed*Sin(angle)
set ud.dmg =BlowAwayDamage(lvl)
call SetUnitMoveSpeed(a,GetUnitDefaultMoveSpeed(a))
call SetUnitPathing(a,false)
call UnitAddFly(a)
set structIndex[id]=ud
endif
endif
endloop
call DestroyEffect(AddSpecialEffect(BlowAwayGFXPath,.wd[i].x,.wd[i].y))
//Destroy Handles
call DestroyLightning(.light[i])
call RemoveUnit(.dummy[i])
call .wd[i].destroy()
set .light[i]=null
set .dummy[i]=null
set i=i+1
endloop
call WardEnd.addMotion(we)
set check=null
endmethod
method IsPointInGravityField takes real x,real y returns boolean
local integer i = 0
local integer j = WardAmount-1
local boolean hit = false
//Check if point is in field
loop
exitwhen i == WardAmount
if (.wd[i].y < y and .wd[j].y >= y) or (.wd[j].y < y and .wd[i].y >= y) then
if (.wd[i].x+(y-.wd[i].y)/(.wd[j].y-.wd[i].y)*(.wd[j].x-.wd[i].x) < x) then
set hit=not hit
endif
endif
set j = i
set i = i + 1
endloop
return hit
endmethod
method motion takes nothing returns nothing
local integer i =0
local integer c =WardAmount-1
local group check =MainFunctions_loopG
local integer lvl =GetUnitAbilityLevel(.caster,SpellId)
local integer id
local UnitDatas ud
local real x
local real y
local boolean zD =false
local unit a
local integer sw
//Effect motion
if not .explosion then
set .currentZ=.currentZ+EffectSpeed
if .currentZ>Animation_XtraFadeZ then
set .fade=.fade-.mfade
endif
if .currentZ>Animation_MaxZ then
set .currentZ=WardZ
set .fade =100.
set zD=true
endif
loop
exitwhen i==WardAmount or .explosion
call SetUnitFlyHeight(.dummy[i],.currentZ,0.)
call MoveLightningEx(.light[i],true,.wd[i].x,.wd[i].y,.currentZ+GetZ(.wd[i].x,.wd[i].y),.wd[c].x,.wd[c].y,.currentZ+GetZ(.wd[c].x,.wd[c].y))
if .currentZ>Animation_XtraFadeZ and .fade>0. then
call SetLightningColor(.light[i],1.,1.,1.,.fade*0.01)
call SetUnitVertexColor(.dummy[i],255,255,255,PercentTo255(.fade))
elseif zD then
call SetLightningColor(.light[i],1.,1.,1.,1.)
call SetUnitVertexColor(.dummy[i],255,255,255,255)
endif
if GetUnitState(.wd[i].ward,UNIT_STATE_LIFE)<=0. then
call .WardExplosion()
endif
set c=i
set i=i+1
endloop
//Check if units are in the near
set check=GetUnitsInRect(.minX,.minY,.maxX,.maxY)
loop
set a=FirstOfGroup(check)
exitwhen a==null
call GroupRemoveUnit(check,a)
if not IsUnitInGroup(a,GravityGroup) and .IsPointInGravityField(GetUnitX(a),GetUnitY(a)) and EnumUnitPlaneFilter(.caster,a) then
set ud=UnitDatas.create()
set ud.z =GetUnitDefaultFlyHeight(a)
set ud.leave =false
set ud.falling=false
set ud.new =true
set ud.dmg =0.
call SetUnitMoveSpeed(a,GetUnitDefaultMoveSpeed(a)*MoveSpeedDecrease(lvl)/100.)
call UnitAddAbility(a,EffectId)
call UnitAddFly(a)
call AddHandleIndex(a)
set structIndex[GetHandleIndex(a)]=ud
call GroupAddUnit(.gravity,a)
call GroupAddUnit(GravityGroup,a)
endif
endloop
endif
//Group Stuff
call GroupAddGroup(.gravity,check)
loop
set a=FirstOfGroup(check)
exitwhen a==null
call GroupRemoveUnit(check,a)
set id=GetHandleIndex(a)
set ud=structIndex[id]
set x=GetUnitX(a)
set y=GetUnitY(a)
if .IsPointInGravityField(x,y) and GetUnitState(a,UNIT_STATE_LIFE)>0. and not .explosion then
//Check if a leaving object is again coming in
if ud.leave then
set ud.leave=false
if ud.z<.currentZ then
set ud.new=true
else
set ud.falling=true
endif
call UnitAddAbility(a,EffectId)
endif
//Check if the object is new
if ud.new then
set ud.z=ud.z+GravityNewSpeed
if ud.z>.currentZ then
set ud.z =.currentZ
set ud.new=false
endif
elseif not ud.falling then
set ud.z=ud.z+EffectSpeed
endif
if zD then
//Check the fall
set ud.falling=true
set ud.new =false
set ud.dmg =Damage(lvl)*(ud.z-WardZ)
elseif ud.dmg>0. and not ud.falling then
set ud.dmg=0.
endif
if ud.falling then
set ud.z=ud.z-GravityLeaveSpeed
if ud.z<=.currentZ then
set ud.z=.currentZ
set ud.falling=false
//Damage fall down
call UnitDamageTarget(.caster,a,ud.dmg,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
call DestroyEffect(AddSpecialEffectTarget(DamageGFXPath,a,DamageGFXAttach))
set ud.dmg =0.
endif
endif
call SetUnitFlyHeight(a,ud.z,0.)
//Check that a object leave
elseif not ud.leave then
set ud.leave=true
set ud.dmg =Damage(lvl)*ud.z+ud.dmg
call UnitRemoveAbility(a,EffectId)
elseif GetUnitState(a,UNIT_STATE_LIFE)<=0. then
call SetUnitMoveSpeed(a,GetUnitDefaultMoveSpeed(a))
call GroupRemoveUnit(.gravity,a)
call GroupRemoveUnit(GravityGroup,a)
call SetUnitFlyHeight(a,GetUnitDefaultFlyHeight(a),Animation_BackRateZ)
else
set ud.z=ud.z-GravityLeaveSpeed
call SetUnitFlyHeight(a,ud.z,0.)
if ud.z<=0. then
//End the leave process
set structIndex[id]=0
call ClearHandleIndex(a)
call DestroyEffect(AddSpecialEffectTarget(DamageGFXPath,a,DamageGFXAttach))
call UnitDamageTarget(.caster,a,ud.dmg,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
call SetUnitMoveSpeed(a,GetUnitDefaultMoveSpeed(a))
call GroupRemoveUnit(.gravity,a)
call GroupRemoveUnit(GravityGroup,a)
call SetUnitFlyHeight(a,GetUnitDefaultFlyHeight(a),Animation_BackRateZ)
endif
endif
endloop
if .explosion and FirstOfGroup(.gravity)==null then
set .active=false
endif
set check=null
endmethod
method endmotion takes nothing returns nothing
call RecycleGroup(.gravity)
set .gravity=null
set .caster =null
call .destroy()
endmethod
//! runtextmacro CostumMotion("WardEffect","motion","endmotion","interval")
endstruct
// The summon animation
private struct SummonAnimation
unit caster
effect array gfx[WardAmount]
WardDatas array wd[WardAmount]
real array distance[WardAmount]
real array tempdistance[WardAmount]
real array speed[WardAmount]
real x
real y
real z
method onDestroy takes nothing returns nothing
local integer i=0
loop
exitwhen i==WardAmount
call DestroyEffect(.gfx[i])
set .gfx[i]=null
set i=i+1
endloop
set .caster=null
endmethod
method motion takes nothing returns nothing
local integer i =0
local integer inactive=0
local real x
local real y
local real z
// Effect Motion
loop
exitwhen i==WardAmount
if .wd[i].animation then
set .tempdistance[i] =.tempdistance[i]+.speed[i]
set x =.wd[i].x+.wd[i].mx
set y =.wd[i].y+.wd[i].my
set z =GetZ(x,y)
set .wd[i].z =Sin((.tempdistance[i]/.distance[i])*3.14159)*Animation_FlyHeight+.z-z
if GetRectMinX(GameArea) <= x and x <= GetRectMaxX(GameArea) and GetRectMinY(GameArea) <= y and y <= GetRectMaxY(GameArea) then
set .wd[i].x=x
set .wd[i].y=y
call SetUnitX(.wd[i].ward,x)
call SetUnitY(.wd[i].ward,y)
endif
call SetUnitFlyHeight(.wd[i].ward,.wd[i].z,0.)
if .wd[i].z<=z or .tempdistance[i]>.distance[i] then
set .wd[i].animation=false
call SetUnitFlyHeight(.wd[i].ward,0.,0.)
endif
else
set inactive=inactive+1
endif
set i=i+1
endloop
if inactive==WardAmount then
set .active=false
endif
endmethod
method endmotion takes nothing returns nothing
local integer i =0
local integer c =WardAmount-1
local player p =GetOwningPlayer(.caster)
local integer lvl =GetUnitAbilityLevel(.caster,SpellId)
local real angle
local WardEffect we=WardEffect.create()
set we.caster =.caster
set we.explosion =false
set we.gravity =GetNextGroup()
set we.currentZ =WardZ
//Create the wards
loop
exitwhen i==WardAmount
set angle =GetUnitFacing(.wd[i].ward)
call RemoveUnit(.wd[i].ward)
set we.wd[i] =.wd[i]
set we.wd[i].ward =CreateUnit(p,WardId,we.wd[i].x,we.wd[i].y,angle)
set we.light[i] =AddLightningEx(Animation_LightGFX,true,we.wd[i].x,we.wd[i].y,WardZ,.wd[c].x,.wd[c].y,WardZ)
set we.dummy[i] =CreateUnit(Player(14),Animation_XtraDummy,we.wd[i].x,we.wd[i].y,angle)
set we.mfade =EffectSpeed-(100./(Animation_MaxZ-Animation_XtraFadeZ))
set we.fade =100.
call SetUnitPathing(we.wd[i].ward,false)
call SetUnitPosition(we.wd[i].ward,we.wd[i].x,we.wd[i].y)
call SetUnitPathing(we.wd[i].ward,true)
call SetUnitX(we.dummy[i],we.wd[i].x)
call SetUnitY(we.dummy[i],we.wd[i].y)
call UnitAddFly(we.dummy[i])
call SetUnitFlyHeight(we.dummy[i],WardZ,0.)
call SetUnitScale(we.dummy[i],Animation_XtraGFXS,Animation_XtraGFXS,Animation_XtraGFXS)
call UnitApplyTimedLife(we.wd[i].ward,WardExperationType,WardDuration(lvl))
//Get the minX/Y and maxX/Y for later
if we.wd[i].x>=we.maxX then
set we.maxX=we.wd[i].x
elseif we.wd[i].x<we.minX then
set we.minX=we.wd[i].x
endif
if we.wd[i].y>=we.maxY then
set we.maxY=we.wd[i].y
elseif we.wd[i].y<we.minY then
set we.minY=we.wd[i].y
endif
set c=i
set i=i+1
endloop
call WardEffect.addMotion(we)
call .destroy()
set p=null
endmethod
//! runtextmacro CostumMotion("SummonAnimation","motion","endmotion","interval")
endstruct
// The throw animation
private struct InitAnimation
unit dummy
unit caster
effect gfx
real x
real y
real z
real mx
real my
real zfactor
real distance
real tempdistance
method onDestroy takes nothing returns nothing
call U2Null(.dummy,0.5)
set .dummy =null
set .caster=null
set .gfx =null
endmethod
//The simple start
method motion takes nothing returns nothing
local real z
if .tempdistance > .distance then
call DestroyEffect(.gfx)
set .active=false
else
set .tempdistance=.tempdistance+Animation_GFXSpeed
set .x=.x+.mx
set .y=.y+.my
set z =Sin((.tempdistance/(.distance*2.))*3.14159)*Animation_FlyHeight+.z-GetZ(.x,.y)
if z<=GetZ(.x,.y) then
call DestroyEffect(.gfx)
set .active=false
else
call SetUnitX(.dummy,.x)
call SetUnitY(.dummy,.y)
call SetUnitFlyHeight(.dummy,z,0.)
endif
endif
endmethod
method endmotion takes nothing returns nothing
local SummonAnimation sani = SummonAnimation.create()
local integer i = 0
local player p = GetOwningPlayer(.caster)
local real angle = 360./WardAmount
local real tempangle = 0.
local real distance = WardTargetDistance(GetUnitAbilityLevel(.caster,SpellId))
local real speed = distance/Animation_Duration*interval
local real z = Sin((.tempdistance/(.distance*2.))*3.14159)*Animation_FlyHeight+.z-GetZ(.x,.y)
set sani.caster = .caster
set sani.x = .x
set sani.y = .y
set sani.z = GetZ(.x,.y)
loop
exitwhen i==WardAmount
set tempangle = angle*i+GetRandomReal(-WardTargetDeviation,WardTargetDeviation)
set sani.wd[i] = WardDatas.create()
set sani.wd[i].ward = CreateUnit(p,DummyId,.x,.y,tempangle)
set sani.wd[i].x = .x
set sani.wd[i].y = .y
set sani.wd[i].z = z
set sani.wd[i].mx = speed*Cos(tempangle*0.01745327)
set sani.wd[i].my = speed*Sin(tempangle*0.01745327)
set sani.wd[i].mz = (z+.z-GetZ(.x,.y))/Animation_Duration*interval
set sani.wd[i].animation = true
set sani.speed[i] = speed
set sani.distance[i] = distance*2
set sani.tempdistance[i] = distance
set sani.gfx[i] = AddSpecialEffectTarget(Animation_SGFXPath,sani.wd[i].ward,Animation_SGFXAtt)
call SetUnitScale(sani.wd[i].ward,Animation_SGFXSize,Animation_SGFXSize,Animation_SGFXSize)
call UnitAddFly(sani.wd[i].ward)
call SetUnitFlyHeight(sani.wd[i].ward,z,0.)
set i=i+1
endloop
call SummonAnimation.addMotion(sani)
call .destroy()
set p=null
endmethod
//! runtextmacro CostumMotion("InitAnimation","motion","endmotion","interval")
endstruct
// Standart stuff
private function DebugBoolexpr takes nothing returns boolean
return true
endfunction
private function Trap_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SpellId
endfunction
private function Trap_Start takes nothing returns nothing
local InitAnimation ani=InitAnimation.create()
local unit u =GetTriggerUnit()
local real x =GetUnitX(u)
local real y =GetUnitY(u)
local real tx =GetSpellTargetX()
local real ty =GetSpellTargetY()
local real angle
local real distance
//Debug
if tx==x and ty==y then
set angle =GetUnitFacing(u)
set distance=0.1
else
set angle =Atan2(ty-y,tx-x)
set distance=D2PXY(x,y,tx,ty)
endif
//Set Animation Variables
set ani.dummy =CreateUnit(Player(14),DummyId,x,y,angle*57.2958279)
set ani.caster =u
set ani.gfx =AddSpecialEffectTarget(Animation_GFXPath,ani.dummy,Animation_GFXAtt)
set ani.tempdistance=60.
set ani.distance =distance
set ani.x =x
set ani.y =y
set ani.z =GetZ(x,y)
set ani.mx =Animation_GFXSpeed*Cos(angle)
set ani.my =Animation_GFXSpeed*Sin(angle)
call SetUnitScale(ani.dummy,Animation_GFXSize,Animation_GFXSize,Animation_GFXSize)
call UnitAddFly(ani.dummy)
//Start Animation Loop
call InitAnimation.addMotion(ani)
//Remove Handles
set u =null
endfunction
//===========================================================================
private function init takes nothing returns nothing
local integer i=0
local unit a
set gg_trg_Magical_Trap=CreateTrigger( )
set GameArea =GetWorldBounds()
set GravityGroup =CreateGroup()
call TriggerAddAction(gg_trg_Magical_Trap,function Trap_Start)
call TriggerAddCondition(gg_trg_Magical_Trap,Condition(function Trap_Conditions))
loop
call TriggerRegisterPlayerUnitEvent(gg_trg_Magical_Trap, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, MainFunctions_filter)
set i = i + 1
exitwhen i == 12
endloop
//Preload Unit
set a=CreateUnit(Player(14),DummyId,0.,0.,0.)
call UnitAddAbility(a,EffectId)
call RemoveUnit(a)
set a=CreateUnit(Player(14),WardId,0.,0.,0.)
call RemoveUnit(a)
//Preload GFX
call Preload(BlowAwayDamageGFXPa)
call Preload(BlowAwayGFXPath)
call Preload(DamageGFXPath)
call Preload(Animation_SGFXPath)
call Preload(Animation_GFXPath)
set a=null
endfunction
endscope