Name | Type | is_array | initial_value |
Creep_Face_Ang | real | Yes | |
Creep_Loc | location | Yes | |
g | group | No | |
Integer | integer | No | |
Temp_Point | location | No | |
TempUnit | unit | No | |
TempUnit2 | unit | No |
//TESH.scrollpos=51
//TESH.alwaysfold=0
//===========================================================================
// A simple handle counter that shows:
// * Maximum handles reached
// * Elapsed seconds
//
// The leaderboard can be accessed with
// HandleCounter_LEADERBOARD
// The clock (timer) can be accessed with
// HandleCounter_CLOCK
//
// This could be useful only if you'd like to see
// if your map is leaking a lot of handles.
// Otherwise it isn't really needed.
//
// Requires a vJASS compiler to work.
//
// To use:
// Create a trigger named HandleCounter,
// convert to custom script and paste this.
//===========================================================================
library HandleCounter2 initializer Init
//===========================================================================
// Configurables
//===========================================================================
globals
// Leaderboard title/name.
private constant string TITLE = "Handle Counter"
// Text that represents the time.
private constant string TIME_TEXT = "Elapsed Time:"
// Should the leaderboard show time as well? True or false.
private constant boolean SHOW_TIME = true
// How often should the handle count update (of course this is not for the clock).
private constant real UPDATE_PERIOD = 0.25
// Number of locations created for better counting result.
private constant integer STACK_END_TRESHOLD = 5
// Player(0) = Player 1 (Red); Player(1) = Player 2 (Blue); etc.
// Player color of the maximum handles text.
private constant player MAX = Player(0)
// Player color of the time text.
private constant player TIME = Player(1)
endglobals
//===========================================================================
// Do not edit bellow this point unless you know what you're doing.
//===========================================================================
globals
public leaderboard LEADERBOARD
public timer CLOCK
private integer CURRENT_HANDLE = 0
private integer MAX_HANDLE = 0
private integer SECONDS = 0
endglobals
private function L2I takes location loc returns integer
return GetHandleId( loc )
endfunction
private function UpdateTime takes nothing returns nothing
set SECONDS = SECONDS + 1
call LeaderboardSetItemLabel(LEADERBOARD, 1, TIME_TEXT)
call LeaderboardSetItemValue(LEADERBOARD, 1, SECONDS)
endfunction
private function Callback takes nothing returns nothing
local location array loc
local integer a = 0
local integer index
local integer prevIndex = 0
local integer next = 0
loop
set loc[a] = Location(0., 0.)
set index = L2I(loc[a]) - 0x100000
set a = a + 1
if index == prevIndex + 1 then
set next = next + 1
else
set next = 0
endif
set prevIndex = index
exitwhen next >= STACK_END_TRESHOLD
endloop
call LeaderboardSetItemValue(LEADERBOARD, 0, index - a)
loop
set a = a - 1
call RemoveLocation(loc[a])
set loc[a] = null
exitwhen a <= 0
endloop
endfunction
private function Actions takes nothing returns nothing
local timer tim = GetExpiredTimer()
set LEADERBOARD = CreateLeaderboard()
call LeaderboardSetLabel(LEADERBOARD, TITLE)
call PlayerSetLeaderboard(GetLocalPlayer(), LEADERBOARD)
call LeaderboardDisplay(LEADERBOARD, true)
call TimerStart(tim, UPDATE_PERIOD, true, function Callback)
call LeaderboardAddItem(LEADERBOARD, "Max Handles", 0, MAX)
call LeaderboardSetSizeByItemCount(LEADERBOARD, 1)
if SHOW_TIME then
set CLOCK = CreateTimer()
call TimerStart(CLOCK, 1., true, function UpdateTime)
call LeaderboardAddItem(LEADERBOARD, "", 1, TIME)
// Prevent leaderboard showing "1" during the first second.
call LeaderboardSetItemLabel(LEADERBOARD, 1, TIME_TEXT)
call LeaderboardSetItemValue(LEADERBOARD, 1, SECONDS)
call LeaderboardSetSizeByItemCount(LEADERBOARD, 2)
endif
set tim = null
endfunction
private function Init takes nothing returns nothing
call TimerStart(CreateTimer() , 0., false, function Actions)
endfunction
endlibrary
//TESH.scrollpos=130
//TESH.alwaysfold=0
library MiscScript initializer onInit requires GroupUtils
globals
private real MinX
private real MaxX
private real MinY
private real MaxY
private real X
private real Y
private real R
private real RANGE
private group Enumer
private integer Int = 0
endglobals
function TrueFilter takes nothing returns boolean
return true
endfunction
function UnitInRangeFilter takes nothing returns boolean
local unit f = GetFilterUnit()
local boolean ok = IsUnitInRangeXY(f,X,Y,RANGE)
set f = null
return ok
endfunction
function GetUnitsInRange takes real x, real y, real r, boolexpr bx returns group
local boolexpr bx2
set X = x
set Y = y
set RANGE = r
set bx2 = Condition( function UnitInRangeFilter )
set bj_lastCreatedGroup = CreateGroup()
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x , y , r+100. , And( bx, bx2) )
call DestroyBoolExpr(bx)
call DestroyBoolExpr(bx2)
set bx2 = null
return bj_lastCreatedGroup
endfunction
function EnumUnitsInRange takes group g, real x, real y, real r, boolexpr bx returns nothing
local boolexpr bx2
set X = x
set Y = y
set RANGE = r
set bx2 = Condition( function UnitInRangeFilter )
call GroupEnumUnitsInRange(g,x,y,r+100., And(bx, bx2) )
call DestroyBoolExpr(bx)
call DestroyBoolExpr(bx2)
set bx2 = null
endfunction
function SetUnitZ takes unit u, real h returns nothing
call UnitAddAbility( u , 'Amrf')
call UnitRemoveAbility( u , 'Amrf' )
call SetUnitFlyHeight( u , h, 0. )
endfunction
function AngleXY takes real x1, real y1, real x2, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
function DistanceXY takes real x1, real y1, real x2, real y2 returns real
return SquareRoot( (x2-x1) * (x2-x1) + (y2-y1) * (y2-y1))
endfunction
function DistanceUnits takes unit a, unit b returns real
local real dx = GetUnitX(b) - GetUnitX(a)
local real dy = GetUnitY(b) - GetUnitY(a)
return SquareRoot(dx * dx + dy * dy)
endfunction
function AngleUnits takes unit a, unit b returns real
return bj_RADTODEG * Atan2(GetUnitY(b) - GetUnitY(a), GetUnitX(b) - GetUnitX(a))
endfunction
function GetPPX takes real x, real dist, real angle returns real
local real X = x + dist * Cos(angle * bj_DEGTORAD)
if X < MinX then
return MinX
endif
if X > MaxX then
return MaxX
endif
return X
endfunction
function GetPPY takes real y, real dist, real angle returns real
local real Y = y + dist * Sin(angle * bj_DEGTORAD)
if Y < MinY then
return MinY
endif
if Y > MaxY then
return MaxY
endif
return Y
endfunction
function DestroyTreesInCircleEnum takes nothing returns nothing
local destructable d=GetEnumDestructable()
if (GetWidgetLife(d)>0) and not(IsDestructableInvulnerable(d)) and ((Pow(GetDestructableX(d)-X,2)+Pow(GetDestructableY(d)-Y,2)) <= R) and (GetDestructableMaxLife(d)==50) then
call KillDestructable(d)
endif
set d=null
endfunction
function DestroyTreesInCircle takes real x, real y, real radius returns nothing
local rect r=Rect(x - radius,y - radius,x + radius,y + radius)
set X=x
set Y=y
set R=radius*radius
call EnumDestructablesInRect(r,null,function DestroyTreesInCircleEnum)
call RemoveRect(r)
set r=null
endfunction
function RemoveUnitDelay takes unit u, real time returns nothing
call TriggerSleepAction( time )
call RemoveUnit( u )
endfunction
function DestroyEffectDelay takes effect e, real time returns nothing
call TriggerSleepAction( time )
call DestroyEffect( e )
endfunction
function GetNearestUnit takes real locx, real locy, real radius, boolexpr unitfilter returns unit
local unit p
local unit p2
local real discurrent = 0.
local real dist = 0.
call GroupEnumUnitsInArea(Enumer,locx,locy,radius,unitfilter)
set bj_lastCreatedUnit = null
set discurrent = radius
loop
set p = FirstOfGroup(Enumer)
exitwhen p == null
call GroupRemoveUnit(Enumer,p)
set dist = DistanceXY( locx, locy, GetUnitX(p), GetUnitY(p) )
if dist < discurrent then
set discurrent = dist
set bj_lastCreatedUnit = p
endif
set p = null
endloop
call GroupRefresh( Enumer )
return bj_lastCreatedUnit
endfunction
private function onInit takes nothing returns nothing
set Enumer = NewGroup()
set MinX = GetRectMinX( bj_mapInitialPlayableArea )
set MaxX = GetRectMaxX( bj_mapInitialPlayableArea )
set MinY = GetRectMinY( bj_mapInitialPlayableArea )
set MaxY = GetRectMaxY( bj_mapInitialPlayableArea )
endfunction
endlibrary
//TESH.scrollpos=88
//TESH.alwaysfold=0
//===============================================================
//| game_war48 Presents
//| Twister
//| ¯¯¯¯¯¯¯
//| Requires:
//| - JassNewGen v1.5d
//| - TimerUtils
//|
//| How to Import:
//| - Copy ability: "Twister" (A002)
//| - Copy unit: Dummy Unit - Twister and Storm Spiral (n001)
//| - Copy trigger: Twister and TimerUtils (if you don't have it)
//| - Changes the raw id of abilities, units,... in the globals.
//| - And MUST remember to change the raw id of XE Dummy in "xebasic"
//|
//| Modification:
//| - Values in the globals block and functions below it
//|
//| Credit
//| - Thanks Vexorian for TimerUtils and xe
//| - Thanks Cohadar for OID
//| - Thanks Tom_Kazansky for helping me
//| - Thanks Tink3 for his template map
//| - Thanks Rising_Dusk for GroupUtils
//===============================================================
scope Twister initializer InitTW
globals
private constant integer ABILITYID = 'A002' // Rawcode of the ability
private constant integer DUMMYID = 'n001' // Rawcode of the "wind" dummy
private constant integer DAMAGEID = 'A001' // Rawcode of the damage ability
private constant integer DAMAGEORDERID = OID_thunderbolt // Order ID of the damage ability from OID Library by Cohadar(important, needed to cast damage ability)
private constant string EFFECTDAMAGE = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl" // Path effect when damage on ground
private constant real FLYHEIGHT = 500. // Maximum height to "fly"
//------------------------------
private constant real PERIOD = 0.04 // period of time, but i think that shouldn't edit this
endglobals
private function GetDamage takes integer lvl returns real
return 200. + 0. * lvl // Damage deals when touching enemy units on ground, configurable
endfunction
//=============================================================================
globals
private integer I
endglobals
//=============================================================================
private struct eo
unit c
unit array d[6]
boolean array inc[6]
boolean b = false
boolean b2 = false
real dx
real dy
real tx
real ty
real df
real array hs[6]
real h = 100.
real hb = 150
real dist
real height = 500
real ang
real array a[6]
real dam
integer tick
integer tk
integer toss
integer lvl
group g
endstruct
private function TwisterG takes nothing returns nothing
local eo d = I
local unit e = GetEnumUnit()
local real x = GetUnitX(e)
local real y = GetUnitY(e)
local real dist = DistanceXY( d.dx, d.dy, x, y )
call SetUnitX( e, GetPPX( d.dx, 100., 0. ) )
call SetUnitY( e, GetPPY( d.dy, 100., 0. ) )
call IssueImmediateOrder( e, "stop" )
if not d.b2 then
if GetUnitFlyHeight(e) < FLYHEIGHT then
call SetUnitZ( e, d.height * Sin( (90/d.tk) * d.tick * bj_DEGTORAD ) )
endif
endif
set e = null
endfunction
private function TwisterUP takes nothing returns nothing
local eo d = I
local xecast xe
local unit e = GetEnumUnit()
local real x = GetUnitX(e)
local real y = GetUnitY(e)
local real z = GetUnitDefaultFlyHeight(e)
set xe = xecast.createBasicA( DAMAGEID, DAMAGEORDERID, GetOwningPlayer( d.c ) )
call xe.setSourcePoint( x, y, 0. )
call xe.castOnTarget( e, d.lvl )
call SetUnitX( e, x )
call SetUnitY( e, y )
//call SetUnitPosition( e, x, y )
call SetUnitZ( e, z )
call DestroyTreesInCircle( x, y, 200 )
set e = null
endfunction
private function TwisterM takes nothing returns nothing
local eo d = I
local unit e = GetEnumUnit()
local real sinr = 90 / 25 * d.tick
local real r1 = d.dist * Sin(sinr * bj_DEGTORAD)
local real dx = GetPPX( d.dx, r1, d.df )
local real dy = GetPPY( d.dy, r1, d.df )
call SetUnitX( e, dx )
call SetUnitY( e, dy )
//call SetUnitPosition( e, dx, dy )
call DestroyTreesInCircle( dx, dy, 200. )
call DestroyEffect( AddSpecialEffect( EFFECTDAMAGE, GetUnitX(e), GetUnitY(e) ) )
set e = null
endfunction
private function TwisterF takes nothing returns boolean
local eo d = I
local unit u = GetFilterUnit()
local boolean ok = false
if IsUnitEnemy (u, GetOwningPlayer(d.c)) /*
*/and IsUnitVisible (u, GetOwningPlayer(d.c)) /*
*/and not IsUnitType (u, UNIT_TYPE_MAGIC_IMMUNE) /*
*/and not IsUnitType (u, UNIT_TYPE_STRUCTURE) /*
*/and not IsUnitType (u, UNIT_TYPE_DEAD) /*
*/and not IsUnitInGroup (u, d.g) then
set ok = true
endif
set u = null
return ok
endfunction
private function TwisterT takes nothing returns nothing
local timer ti = GetExpiredTimer()
local eo d = GetTimerData(ti)
local group g
local unit p
local integer i
local integer j
local integer k
local real dx
local real dy
local real h
local real sinr
local real r1
if d.toss == 2 then
if d.tick < 0 then
set j = 0
loop
exitwhen j > 5
call KillUnit(d.d[j])
set j = j + 1
endloop
set I = d
call ForGroup(d.g, function TwisterUP)
call ReleaseGroup(d.g)
call ReleaseTimer(ti)
set ti = null
call d.destroy()
return
endif
endif
if d.toss == 0 then
if d.tick > 25 then
set d.dx = d.tx
set d.dy = d.ty
call GroupEnumUnitsInArea(d.g, d.dx, d.dy, 300., Condition(function TwisterF) )
set k = 0
loop
exitwhen k > 5
set d.a[k] = 60 * k
set k = k + 1
endloop
set d.tick = 0
set d.toss = 2
set d.hb = 0
set p = null
endif
endif
if d.toss == 0 then
set sinr = 90 / 25 * d.tick
set r1 = d.dist * Sin(sinr * bj_DEGTORAD)
set dx = GetPPX( d.dx, r1, d.df )
set dy = GetPPY( d.dy, r1, d.df )
endif
set i = 0
loop
set i = i + 1
exitwhen i > 8
set j = 0
loop
exitwhen j > 5
if d.toss == 0 then
//*****************************************************
if d.inc[j] and d.hs[j] == 1 then
set d.inc[j] = false
endif
if not d.inc[j] and d.hs[j] == -1 then
set d.inc[j] = true
endif
if d.inc[j] then
set d.hs[j] = d.hs[j] + 0.05
else
set d.hs[j] = d.hs[j] - 0.05
endif
call SetUnitX(d.d[j],GetPPX( dx, d.h * d.hs[j], d.df - 90. ) )
call SetUnitY(d.d[j],GetPPY( dy, d.h * d.hs[j], d.df - 90. ) )
call DestroyTreesInCircle( dx, dy, 200. )
set h = SquareRoot( d.h * d.h - d.h * d.hs[j] * d.h * d.hs[j] )
if d.inc[j] then
call SetUnitZ(d.d[j], d.hb + h )
else
call SetUnitZ(d.d[j], d.hb - h )
endif
//*****************************************************
endif
set j = j + 1
endloop
endloop
set j = 0
loop
exitwhen j > 5
if d.toss == 2 then
if d.tick >= 50 then
set d.height = 0
set d.tk = 5
set d.tick = 5
set d.b2 = true
else
set d.height = FLYHEIGHT
set d.tk = 50
endif
if d.a[j] >= 360 then
set d.a[j] = 0.
else
set d.a[j] = d.a[j] + 10.
endif
if not d.b2 then
call SetUnitX(d.d[j],GetPPX( d.dx, 250., d.a[j] ) )
call SetUnitY(d.d[j],GetPPY( d.dy, 250., d.a[j] ) )
call SetUnitZ(d.d[j], d.height * Sin( (90/d.tk) * d.tick * bj_DEGTORAD ) )
else
call SetUnitZ(d.d[j], d.height * Sin( (90/d.tk) * d.tick * bj_DEGTORAD ) + 10 )
endif
call DestroyTreesInCircle( d.dx, d.dy, 200. )
set I = d
call ForGroup(d.g, function TwisterG)
endif
set j = j + 1
endloop
if d.toss == 0 then
set g = NewGroup()
set I = d
call GroupEnumUnitsInArea(g, dx, dy, 200., Condition(function TwisterF) )
loop
set p = FirstOfGroup(g)
exitwhen p == null
call GroupRemoveUnit(g, p)
call GroupAddUnit(d.g, p)
call UnitDamageTarget(d.c, p, d.dam, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_DIVINE, null)
endloop
call ReleaseGroup(g)
set g = null
set I = d
call ForGroup(d.g, function TwisterM)
endif
if d.b2 then
set d.tick = d.tick - 1
else
set d.tick = d.tick + 1
endif
//set ti = null
endfunction
private function Twister takes nothing returns nothing
local eo d = eo.create()
local timer ti = NewTimer()
set d.c = GetTriggerUnit()
set d.dx = GetUnitX(d.c)
set d.dy = GetUnitY(d.c)
set d.tx = GetSpellTargetX()
set d.ty = GetSpellTargetY()
set d.df = AngleXY( d.dx, d.dy, d.tx, d.ty )
set d.dist = DistanceXY( d.dx, d.dy, d.tx, d.ty )
set d.hs[0] = 1
set d.d[0] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[0],d.df-90.),GetPPY(d.dy,d.h*d.hs[0],d.df-90.),d.df-90)
call SetUnitZ(d.d[0],d.hb)
call SetUnitVertexColor(d.d[0], 255, 255, 255, 0)
set d.inc[0] = true
set d.hs[1] = -1
set d.d[1] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[1],d.df+90.),GetPPY(d.dy,d.h*d.hs[1],d.df+90.),d.df+90)
call SetUnitZ(d.d[1],d.hb)
call SetUnitVertexColor(d.d[1], 255, 255, 255, 0)
set d.inc[1] = false
set d.hs[2] = 0.
set d.d[2] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[2],d.df+90.),GetPPY(d.dy,d.h*d.hs[2],d.df+90.),d.df+90)
call SetUnitZ(d.d[2],d.hb+d.h)
call SetUnitVertexColor(d.d[2], 255, 255, 255, 0)
set d.inc[2] = true
set d.hs[3] = 0.
set d.d[3] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[3],d.df+90.),GetPPY(d.dy,d.h*d.hs[3],d.df+90.),d.df+90)
call SetUnitZ(d.d[3],d.hb-d.h)
call SetUnitVertexColor(d.d[3], 255, 255, 255, 0)
set d.inc[3] = false
set d.hs[4] = 0.5
set d.d[4] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[4],d.df-90.),GetPPY(d.dy,d.h*d.hs[4],d.df-90.),d.df-90)
call SetUnitZ(d.d[4],d.hb)
call SetUnitVertexColor(d.d[4], 255, 255, 255, 0)
set d.inc[4] = true
set d.hs[5] = -0.5
set d.d[5] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[5],d.df+90.),GetPPY(d.dy,d.h*d.hs[5],d.df+90.),d.df+90)
call SetUnitZ(d.d[5],d.hb)
call SetUnitVertexColor(d.d[5], 255, 255, 255, 0)
set d.inc[5] = false
set d.lvl = GetUnitAbilityLevel( d.c, ABILITYID )
set d.toss = 0
set d.tick = 0
set d.dam = GetDamage( d.lvl )
set d.g = NewGroup()
call SetTimerData( ti, d )
call TimerStart( ti, PERIOD, true, function TwisterT )
//set ti = null
endfunction
private function TwisterC takes nothing returns boolean
return GetSpellAbilityId() == ABILITYID
endfunction
//===========================================================================
private function InitTW takes nothing returns nothing
local trigger TrigTW = CreateTrigger( )
local integer index
set index = 0
loop
call TriggerRegisterPlayerUnitEvent( TrigTW, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition( TrigTW, Condition( function TwisterC ) )
call TriggerAddAction( TrigTW, function Twister )
call XE_PreloadAbility( DAMAGEID )
//set TrigTW = null
endfunction
endscope
//TESH.scrollpos=25
//TESH.alwaysfold=0
//===============================================================
//| game_war48 Presents
//| Storm Spiral
//| ¯¯¯¯¯¯¯¯¯¯¯¯
//| Requires:
//| - JassNewGen v1.5d
//| - TimerUtils (red+blue+orange flavors for 1.24b+) by Vexorian
//| - Damage Over Time v1.7 by Dynasti on hiveworkshop.com
//|
//| How to Import:
//| - Copy ability: "Storm Spiral" (A000)
//| - Copy unit: Dummy Unit - Twister and Storm Spiral (n001)
//| - Copy trigger: Storm Spiral and TimerUtils, DOT (if you don't have it)
//| - Changes the raw id of abilities, units,... in the globals.
//|
//| Modification:
//| - Values in the globals block and functions below it
//|
//| Credit
//| - Thanks Vexorian for TimerUtils
//| - Thanks Tom_Kazansky for helping me
//| - Thanks Tink3 for his template map
//| - Thanks Dynasti for his system
//| - Thanks Rising_Dusk for his system
//===============================================================
scope StormSpiral initializer InitSS
globals
private constant integer ABILITYID = 'A000' // Rawcode of the ability
private constant integer DUMMYID = 'n001' // Rawcode of the dummy
private constant string EFFECTDAMAGE1 = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl" // Path effect when damage
private constant string EFFECTDAMAGE2 = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl" // Path effect when damage, too
private constant string EFFECTDAMAGE1ATTACH = "chest" // EffectDamage1 attachment point on unit
private constant string EFFECTDAMAGE2ATTACH = "chest" // EffectDamage2 attachment point on unit
//----------------------------
private constant real PERIOD = 0.04 // period of time, but i think that shouldn't edit this
endglobals
private function GetDamage takes integer lvl returns real
return 300. + 100. * lvl // spell's damage, configurable
endfunction
//=====================================================================
globals
private group GROUP
private integer I
private integer I2
endglobals
private struct ss
unit c
unit d
unit d2
group gc
real dx
real dy
real tx
real ty
real height
real dis
real ang
real a
real a2
real dam
real dps
integer tick
integer toss
endstruct
private function StormSpiralF takes nothing returns boolean
local ss d = I
local unit u = GetFilterUnit()
local boolean ok = false
if IsUnitEnemy(u, GetOwningPlayer(d.c)) /*
*/ and IsUnitVisible(u, GetOwningPlayer(d.c)) /*
*/ and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) /*
*/ and not IsUnitType(u, UNIT_TYPE_STRUCTURE) /*
*/ and not IsUnitType(u, UNIT_TYPE_DEAD) /*
*/ and not IsUnitInGroup(u, GROUP) then
set ok = true
endif
set u = null
return ok
endfunction
private function StormSpiralD takes nothing returns nothing
local unit e = GetEnumUnit()
call GroupRemoveUnit( GROUP, e )
set e = null
endfunction
private function StormSpiralG takes nothing returns nothing
local ss d = I
local unit e = GetEnumUnit()
call SetUnitX( e, GetPPX( GetUnitX( e ), 15., d.ang ) )
call SetUnitY( e, GetPPY( GetUnitY( e ), 15., d.ang ) )
call DestroyEffect( AddSpecialEffectTarget( EFFECTDAMAGE1, e, EFFECTDAMAGE1ATTACH ) )
call DestroyEffect( AddSpecialEffectTarget( EFFECTDAMAGE2, e, EFFECTDAMAGE2ATTACH ) )
set e = null
endfunction
private function StormSpiralT takes nothing returns nothing
local timer ti = GetExpiredTimer()
local ss d = GetTimerData(ti)
local real x
local real y
local unit v
if d.toss == 1 then
if d.tick <= 0 then
call ForGroup( d.gc, function StormSpiralD )
if GROUP != null then
call ReleaseGroup( GROUP )
set GROUP = null
endif
call KillUnit( d.d )
call KillUnit( d.d2 )
call ReleaseGroup( d.gc )
call ReleaseTimer(ti)
set ti = null
call d.destroy()
return
endif
endif
if d.toss == 0 then
if d.tick < 0 then
call SetUnitZ( d.d, 0. )
set d.d2 = CreateUnit( GetOwningPlayer( d.c ), DUMMYID, GetUnitX( d.d ), GetUnitY( d.d ), 0. )
call SetUnitVertexColor( d.d2, 255, 255, 255, 0 )
set d.dx = GetPPX( d.tx, 50., d.ang )
set d.dy = GetPPY( d.ty, 50., d.ang )
set d.a = 0.
set d.a2 = 180.
set d.toss = 1
set d.tick = 50
endif
endif
if d.toss == 0 then
set d.height = d.height - 22.5
set d.dis = d.dis - 15.
set d.a = d.a - 9.
set x = GetPPX( d.tx, d.dis, d.a )
set y = GetPPY( d.ty, d.dis, d.a )
call SetUnitX( d.d, x )
call SetUnitY( d.d, y )
call SetUnitZ( d.d, d.height )
elseif d.toss == 1 then
set d.a = d.a + 30.
set x = GetPPX( d.dx, 50., d.a )
set y = GetPPY( d.dy, 50., d.a )
call SetUnitX( d.d, x )
call SetUnitY( d.d, y )
set d.a2 = d.a2 + 30.
set x = GetPPX( d.dx, 50., d.a2 )
set y = GetPPY( d.dy, 50., d.a2 )
call SetUnitX( d.d2, x )
call SetUnitY( d.d2, y )
set I = d
set v = GetNearestUnit( d.dx, d.dy, 100., Condition( function StormSpiralF ) )
if v != null then
call DamageOverTime( d.c, v, d.dam, d.tick * PERIOD, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_DIVINE )
call GroupAddUnit( GROUP, v )
call GroupAddUnit( d.gc, v )
endif
set I = d
call ForGroup( d.gc, function StormSpiralG )
set d.dx = GetPPX( d.dx, 10., d.ang )
set d.dy = GetPPY( d.dy, 10., d.ang )
endif
set d.tick = d.tick - 1
//set ti = null
endfunction
private function StormSpiral takes nothing returns nothing
local ss d
local timer ti
local integer i
local real x
local real y
set GROUP = NewGroup()
set i = 0
loop
exitwhen i > 17
set d = ss.create()
set d.c = GetTriggerUnit()
set d.tx = GetSpellTargetX()
set d.ty = GetSpellTargetY()
set d.a = 20 * i
set d.ang = d.a
set d.dx = GetPPX( d.tx, 600., d.a )
set d.dy = GetPPY( d.ty, 600., d.a )
set d.height = 950.
set d.dis = 600.
set d.d = CreateUnit( GetOwningPlayer( d.c ), DUMMYID, d.dx, d.dy, 0. )
call SetUnitVertexColor( d.d, 255, 255, 255, 0 )
call SetUnitZ( d.d, d.height )
set d.gc = NewGroup()
set d.toss = 0
set d.tick = 40
set d.dam = GetDamage( GetUnitAbilityLevel( d.c, ABILITYID ) )
set ti = NewTimer()
call SetTimerData( ti, d )
call TimerStart( ti, PERIOD, true, function StormSpiralT )
//set ti = null
set i = i + 1
endloop
endfunction
private function StormSpiralC takes nothing returns boolean
return GetSpellAbilityId() == ABILITYID
endfunction
//===========================================================================
private function InitSS takes nothing returns nothing
local trigger TrigSS = CreateTrigger( )
local integer index
set index = 0
loop
call TriggerRegisterPlayerUnitEvent( TrigSS, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null )
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition( TrigSS, Condition( function StormSpiralC ) )
call TriggerAddAction( TrigSS, function StormSpiral )
//set TrigSS = null
endfunction
endscope
//TESH.scrollpos=189
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//* [group] ENUM_GROUP As you might expect, this group is good for
//* when you need a group just for enumeration.
//* [boolexpr] BOOLEXPR_TRUE This is a true boolexpr, which is important
//* because a 'null' boolexpr in enumeration
//* calls results in a leak. Use this instead.
//* [boolexpr] BOOLEXPR_FALSE This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//* local group MyGroup = NewGroup()
//* call GroupRefresh(MyGroup)
//* call ReleaseGroup(MyGroup)
//* call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//* call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
//If you don't have xebasic in your map, this value will be used instead.
//This value corresponds to the max collision size of a unit in your map.
private constant real MAX_COLLISION_SIZE = 197.
//If you are insane and don't care about any of the protection involved in
//this library, but want this script to be really fast, set this to true.
private constant boolean LESS_SAFETY = false
endglobals
globals
//* Constants that are available to the user
group ENUM_GROUP = CreateGroup()
boolexpr BOOLEXPR_TRUE = null
boolexpr BOOLEXPR_FALSE = null
endglobals
globals
//* Hashtable for debug purposes
private hashtable ht = InitHashtable()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Arrays and counter for the group stack
private group array Groups
private integer Count = 0
//* Variables for use with the GroupUnitsInArea function
private real X = 0.
private real Y = 0.
private real R = 0.
private hashtable H = InitHashtable()
endglobals
private function HookDestroyGroup takes group g returns nothing
if g == ENUM_GROUP then
call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
endif
endfunction
debug hook DestroyGroup HookDestroyGroup
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
static if not LESS_SAFETY then
call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
endif
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer id = GetHandleId(g)
static if LESS_SAFETY then
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
else
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif not HaveSavedInteger(ht, 0, id) then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
return false
elseif LoadInteger(ht, 0, id) == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
call SaveInteger(ht, 0, id, 2)
endif
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
return true
endfunction
private function Filter takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction
private function HookDestroyBoolExpr takes boolexpr b returns nothing
local integer bid = GetHandleId(b)
if HaveSavedHandle(H, 0, bid) then
//Clear the saved boolexpr
call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
call RemoveSavedHandle(H, 0, bid)
endif
endfunction
hook DestroyBoolExpr HookDestroyBoolExpr
private constant function GetRadius takes real radius returns real
static if LIBRARY_xebasic then
return radius+XE_MAX_COLLISION_SIZE
else
return radius+MAX_COLLISION_SIZE
endif
endfunction
function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
local integer bid = 0
//Set variables to new values
set X = x
set Y = y
set R = radius
if filter == null then
//Adjusts for null boolexprs passed to the function
set filter = Condition(function Filter)
else
//Check for a saved boolexpr
set bid = GetHandleId(filter)
if HaveSavedHandle(H, 0, bid) then
//Set the filter to use to the saved one
set filter = LoadBooleanExprHandle(H, 0, bid)
else
//Create a new And() boolexpr for this filter
set filter = And(Condition(function Filter), filter)
call SaveBooleanExprHandle(H, 0, bid, filter)
endif
endif
//Enumerate, if they want to use the boolexpr, this lets them
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
//Set variables to new values
set X = x
set Y = y
set R = radius
//Enumerate
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
private function True takes nothing returns boolean
return true
endfunction
private function False takes nothing returns boolean
return false
endfunction
private function Init takes nothing returns nothing
set BOOLEXPR_TRUE = Condition(function True)
set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
// o o o o o o o o o o o o o o o o o o o o o o o
// o Damage Over Time by Dynasti o Version 1.7 o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
// o How To Implement o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
// o o
// o 1. - Make sure that you opened the system in the newest version of JNGP o
// o 2. - Copy this trigger into you map o
// o o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
// o How to Use o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
// o o
// o - This system requires you to give 8 variables for it to function perfectly. o
// o Variables are: o
// o 1. - A unit that does the damage, lets call it " A " o
// o 2. - A widget that is given the damage, lets call it " B " o
// o 3. - A real value that is the damage, lets call it " D " o
// o 4. - A real value that is the time it takes to do the damage, lets call it " T " o
// o 5. - An attacktype that is used to regulate the damage, lets call it " AT " o
// o 6. - A damagetype that is used to regulate the damage, lets call it " DT " o
// o 7. - A string that is the model of the period effect, lets call it " EX " o
// o 8. - A string that is the attachment for the " EX " string, lets call it " ExAttach " o
// o o
// o The call: o
// o call DamageOverTimeEx( A , B , D , T , AT , DT , EX , ExAttach ) o
// o you have now succesfully called the function and started the damage over time. o
// o o
// o if you want something simpler and not have the effect do this: o
// o call DamageOverTime( A , B , D , T , AT , DT ) o
// o now you have done the simpler call. o
// o o
// o Tips: o
// o To not make the target " B " run away or run after you, do this: o
// o call DamageOverTimeEx( B , B , D , T , AT , DT , EX , ExAttach ) o
// o Or for the simpler call: o
// o call DamageOverTime( B , B , D , T , AT , DT ) o
// o o
// o What we now have done is set the unit that does the damage to the unit that takes the damage, " B ". o
// o This does so that the unit " B " does damage to itself and will not run away or attack any unit. o
// o NB: Damaging itself will result to bounty for the own dying unit or, no bounty at all for the killer. o
// o o
// o o
// o If for any reason you want to cancel you need to save the DOT struct as a variable in whatever you're using. o
// o o
// o First, you need to have the DOT struct variable stored as some integer to cancel a DOT. o
// o Example: o
// o [...] o
// o set SomeInteger = DamageOverTime(A, B, D, T, AT, DT, EX, ExAttach) o
// o o
// o Since function DamageOverTimeEx or DamageOverTime returns the struct to you, you can store it for later use o
// o IMPORTANT!: If you do the stopcall after the DoT has stopped you might screw up things. To do this, you o
// o can use the "check" function to check if the struct value you have stored is running and to o
// o what unit. o
// o o
// o The "Check" function: o
// o the function "IsDamageRunning takes DOT dat returns unit" will return 'null' as a value if the struct isn't o
// o running, and will return a unit handle if the struct is running. But wait, you might be thinking: o
// o What if it is another unit than the unit I started it with?! Well do this: o
// o [...] o
// o if MyUnitVariable == IsDamageRunning(StructVariable) then o
// o [your actions here] o
// o call EndDamageOverTime(StructVariable) o
// o else o
// o set StructVariable = 0 o
// o endif o
// o o
// o By doing this, it will insure you that you won't accedently end another unit's DOT effect o
// o o
// o o
// o - For more info go to: www.HiveWorkshop.com or visit www.Ngo.clan.su , user at both sites are Dynasti o
// o o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
library DOT initializer Init requires TimerUtils
globals
private constant integer FPS = 40 // This is how many times the struct loop will run in a single second. 30-40 is recomended
// DO NOT TUCH! =)
private constant real Interval = (1.0 / FPS)
endglobals
private struct DOT
unit Attacker
widget Target
real Damage
integer EndCount
attacktype AttackType
damagetype DamageType
effect Effect
static integer array Index
static integer Total = 0
static timer Tim = null
static integer Count = -2147483648 // Just a random low number, it is needed
static method Loop takes nothing returns nothing
local DOT dat
local integer i = 0
set DOT.Count = DOT.Count + 1
loop
exitwhen i >= DOT.Total
set dat = DOT.Index[i]
if DOT.Count > dat.EndCount or GetWidgetLife(dat.Target) <= .405 then
call DestroyEffect(dat.Effect)
set dat.Effect = null
set dat.Attacker = null
set dat.Target = null
set dat.AttackType = null
set dat.DamageType = null
call dat.destroy()
set DOT.Total = DOT.Total - 1
set DOT.Index[i] = DOT.Index[DOT.Total]
set i = i - 1
else
call UnitDamageTarget(dat.Attacker, dat.Target, dat.Damage, false, false, dat.AttackType, dat.DamageType, null)
endif
set i = i + 1
endloop
if DOT.Total == 0 then
call PauseTimer(DOT.Tim)
endif
endmethod
static method Start takes unit Attacker, widget Target, real Damage, real Time, attacktype AttackType, damagetype DamageType, string Effect, string EffectAttach returns DOT
local DOT dat = DOT.allocate()
set dat.Attacker = Attacker
set dat.Target = Target
set dat.AttackType = AttackType
set dat.DamageType = DamageType
if Effect != "" and Effect != null then
if EffectAttach != "" and EffectAttach != null then
set dat.Effect = AddSpecialEffectTarget(Effect, Target, EffectAttach)
endif
endif
set dat.Damage = Damage * Interval / Time
set dat.EndCount = DOT.Count + R2I(Time / Interval)
if DOT.Total == 0 then
call TimerStart(DOT.Tim, Interval, true, function DOT.Loop)
endif
set DOT.Index[DOT.Total] = dat
set DOT.Total = DOT.Total + 1
return dat
endmethod
endstruct
//=========================================================================================
function DamageOverTimeEx takes unit Attacker, widget Target, real Damage, real Time, attacktype AttackType, damagetype DamageType, string Effect, string EffectAttach returns DOT
return DOT.Start(Attacker, Target, Damage, Time, AttackType, DamageType, Effect, EffectAttach)
endfunction
function DamageOverTime takes unit Attacker, widget Target, real Damage, real Time, attacktype AttackType, damagetype DamageType returns DOT
return DOT.Start(Attacker, Target, Damage, Time, AttackType, DamageType, "", "")
endfunction
function EndDamageOverTime takes DOT dat returns nothing
set dat.EndCount = DOT.Count + 1
endfunction
function IsDamageRunning takes DOT dat returns widget
return dat.Target
endfunction
//=========================================================================================
private function Init takes nothing returns nothing
set DOT.Tim = NewTimer()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = false
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
set tT[0]=CreateTimer()
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=299
//TESH.alwaysfold=0
//==============================================================================
// OIDs -- OrderIDs by Cohadar -- v1.1
//==============================================================================
//
// PURPOUSE:
// * Just a bounch of usefull constants
// * I guess the most common use would be ordering a dummy caster
//
// THANKS TO: ???
// * I totally stole these constants from someones .xls file.
// * Unfortunately I forgot whose file it was (probably PipeDream or PitzerMike)
//
// * If someone finds an order not mentioned here please let me know so I can add it.
//
// HOW TO IMPORT:
// * Just create a trigger named OIDs
// * then convert it to text and replace the whole trigger text with this one
//
//==============================================================================
library OID
globals
public constant integer absorb = 852529
public constant integer acolyteharvest = 852185
public constant integer AImove = 851988
public constant integer ambush = 852131
public constant integer ancestralspirit = 852490
public constant integer ancestralspirittarget = 852491
public constant integer animatedead = 852217
public constant integer antimagicshell = 852186
public constant integer attack = 851983
public constant integer attackground = 851984
public constant integer attackonce = 851985
public constant integer attributemodskill = 852576
public constant integer auraunholy = 852215
public constant integer auravampiric = 852216
public constant integer autodispel = 852132
public constant integer autodispeloff = 852134
public constant integer autodispelon = 852133
public constant integer autoentangle = 852505
public constant integer autoentangleinstant = 852506
public constant integer autoharvestgold = 852021
public constant integer autoharvestlumber = 852022
public constant integer avatar = 852086
public constant integer avengerform = 852531
public constant integer awaken = 852466
public constant integer banish = 852486
public constant integer barkskin = 852135
public constant integer barkskinoff = 852137
public constant integer barkskinon = 852136
public constant integer battleroar = 852599
public constant integer battlestations = 852099
public constant integer bearform = 852138
public constant integer berserk = 852100
public constant integer blackarrow = 852577
public constant integer blackarrowoff = 852579
public constant integer blackarrowon = 852578
public constant integer blight = 852187
public constant integer blink = 852525
public constant integer blizzard = 852089
public constant integer bloodlust = 852101
public constant integer bloodlustoff = 852103
public constant integer bloodluston = 852102
public constant integer board = 852043
public constant integer breathoffire = 852580
public constant integer breathoffrost = 852560
public constant integer build = 851994
public constant integer burrow = 852533
public constant integer cannibalize = 852188
public constant integer carrionscarabs = 852551
public constant integer carrionscarabsinstant = 852554
public constant integer carrionscarabsoff = 852553
public constant integer carrionscarabson = 852552
public constant integer carrionswarm = 852218
public constant integer chainlightning = 852119
public constant integer channel = 852600
public constant integer charm = 852581
public constant integer cloudoffog = 852473
public constant integer clusterrockets = 852652
public constant integer coldarrows = 852244
public constant integer coldarrowstarg = 852243
public constant integer controlmagic = 852474
public constant integer corporealform = 852493
public constant integer corrosivebreath = 852140
public constant integer coupleinstant = 852508
public constant integer coupletarget = 852507
public constant integer creepanimatedead = 852246
public constant integer creepdevour = 852247
public constant integer creepheal = 852248
public constant integer creephealoff = 852250
public constant integer creephealon = 852249
public constant integer creepthunderbolt = 852252
public constant integer creepthunderclap = 852253
public constant integer cripple = 852189
public constant integer curse = 852190
public constant integer curseoff = 852192
public constant integer curseon = 852191
public constant integer cyclone = 852144
public constant integer darkconversion = 852228
public constant integer darkportal = 852229
public constant integer darkritual = 852219
public constant integer darksummoning = 852220
public constant integer deathanddecay = 852221
public constant integer deathcoil = 852222
public constant integer deathpact = 852223
public constant integer decouple = 852509
public constant integer defend = 852055
public constant integer detectaoe = 852015
public constant integer detonate = 852145
public constant integer devour = 852104
public constant integer devourmagic = 852536
public constant integer disassociate = 852240
public constant integer disenchant = 852495
public constant integer dismount = 852470
public constant integer dispel = 852057
public constant integer divineshield = 852090
public constant integer doom = 852583
public constant integer drain = 852487
public constant integer dreadlordinferno = 852224
public constant integer dropitem = 852001
public constant integer drunkenhaze = 852585
public constant integer earthquake = 852121
public constant integer eattree = 852146
public constant integer elementalfury = 852586
public constant integer ensnare = 852106
public constant integer ensnareoff = 852108
public constant integer ensnareon = 852107
public constant integer entangle = 852147
public constant integer entangleinstant = 852148
public constant integer entanglingroots = 852171
public constant integer etherealform = 852496
public constant integer evileye = 852105
public constant integer faeriefire = 852149
public constant integer faeriefireoff = 852151
public constant integer faeriefireon = 852150
public constant integer fanofknives = 852526
public constant integer farsight = 852122
public constant integer fingerofdeath = 852230
public constant integer firebolt = 852231
public constant integer flamestrike = 852488
public constant integer flamingarrows = 852174
public constant integer flamingarrowstarg = 852173
public constant integer flamingattack = 852540
public constant integer flamingattacktarg = 852539
public constant integer flare = 852060
public constant integer forceboard = 852044
public constant integer forceofnature = 852176
public constant integer forkedlightning = 852587
public constant integer freezingbreath = 852195
public constant integer frenzy = 852561
public constant integer frenzyoff = 852563
public constant integer frenzyon = 852562
public constant integer frostarmor = 852225
public constant integer frostarmoroff = 852459
public constant integer frostarmoron = 852458
public constant integer frostnova = 852226
public constant integer getitem = 851981
public constant integer gold2lumber = 852233
public constant integer grabtree = 852511
public constant integer harvest = 852018
public constant integer heal = 852063
public constant integer healingward = 852109
public constant integer healingwave = 852501
public constant integer healoff = 852065
public constant integer healon = 852064
public constant integer hex = 852502
public constant integer holdposition = 851993
public constant integer holybolt = 852092
public constant integer howlofterror = 852588
public constant integer humanbuild = 851995
public constant integer immolation = 852177
public constant integer impale = 852555
public constant integer inferno = 852232
public constant integer innerfire = 852066
public constant integer innerfireoff = 852068
public constant integer innerfireon = 852067
public constant integer instant = 852200
public constant integer invisibility = 852069
public constant integer illusion = 852274
public constant integer lightningshield = 852110
public constant integer load = 852046
public constant integer loadarcher = 852142
public constant integer loadcorpse = 852050
public constant integer loadcorpseinstant = 852053
public constant integer locustswarm = 852556
public constant integer lumber2gold = 852234
public constant integer magicdefense = 852478
public constant integer magicleash = 852480
public constant integer magicundefense = 852479
public constant integer manaburn = 852179
public constant integer manaflareoff = 852513
public constant integer manaflareon = 852512
public constant integer manashieldoff = 852590
public constant integer manashieldon = 852589
public constant integer massteleport = 852093
public constant integer mechanicalcritter = 852564
public constant integer metamorphosis = 852180
public constant integer militia = 852072
public constant integer militiaconvert = 852071
public constant integer militiaoff = 852073
public constant integer militiaunconvert = 852651
public constant integer mindrot = 852565
public constant integer mirrorimage = 852123
public constant integer monsoon = 852591
public constant integer mount = 852469
public constant integer mounthippogryph = 852143
public constant integer move = 851986
public constant integer nagabuild = 852467
public constant integer neutraldetectaoe = 852023
public constant integer neutralinteract = 852566
public constant integer neutralspell = 852630
public constant integer nightelfbuild = 851997
public constant integer orcbuild = 851996
public constant integer parasite = 852601
public constant integer parasiteoff = 852603
public constant integer parasiteon = 852602
public constant integer patrol = 851990
public constant integer phaseshift = 852514
public constant integer phaseshiftinstant = 852517
public constant integer phaseshiftoff = 852516
public constant integer phaseshifton = 852515
public constant integer phoenixfire = 852481
public constant integer phoenixmorph = 852482
public constant integer poisonarrows = 852255
public constant integer poisonarrowstarg = 852254
public constant integer polymorph = 852074
public constant integer possession = 852196
public constant integer preservation = 852568
public constant integer purge = 852111
public constant integer rainofchaos = 852237
public constant integer rainoffire = 852238
public constant integer raisedead = 852197
public constant integer raisedeadoff = 852199
public constant integer raisedeadon = 852198
public constant integer ravenform = 852155
public constant integer recharge = 852157
public constant integer rechargeoff = 852159
public constant integer rechargeon = 852158
public constant integer rejuvenation = 852160
public constant integer renew = 852161
public constant integer renewoff = 852163
public constant integer renewon = 852162
public constant integer repair = 852024
public constant integer repairoff = 852026
public constant integer repairon = 852025
public constant integer replenish = 852542
public constant integer replenishlife = 852545
public constant integer replenishlifeoff = 852547
public constant integer replenishlifeon = 852546
public constant integer replenishmana = 852548
public constant integer replenishmanaoff = 852550
public constant integer replenishmanaon = 852549
public constant integer replenishoff = 852544
public constant integer replenishon = 852543
public constant integer request_hero = 852239
public constant integer requestsacrifice = 852201
public constant integer restoration = 852202
public constant integer restorationoff = 852204
public constant integer restorationon = 852203
public constant integer resumebuild = 851999
public constant integer resumeharvesting = 852017
public constant integer resurrection = 852283 // was 852094
public constant integer returnresources = 852020
public constant integer revenge = 852241
public constant integer revive = 852039
public constant integer roar = 852164
public constant integer robogoblin = 852656
public constant integer root = 852165
public constant integer sacrifice = 852205
public constant integer sanctuary = 852569
public constant integer scout = 852181
// mine custom
public constant integer scrollofspeed = 852285
public constant integer selfdestruct = 852040
public constant integer selfdestructoff = 852042
public constant integer selfdestructon = 852041
public constant integer sentinel = 852182
public constant integer setrally = 851980
public constant integer shadowsight = 852570
public constant integer shadowstrike = 852527
public constant integer shockwave = 852125
public constant integer silence = 852592
public constant integer sleep = 852227
public constant integer slow = 852075
public constant integer slowoff = 852077
public constant integer slowon = 852076
public constant integer soulpreservation = 852242
public constant integer spellshield = 852571
public constant integer spellshieldaoe = 852572
public constant integer spellsteal = 852483
public constant integer spellstealoff = 852485
public constant integer spellstealon = 852484
public constant integer spies = 852235
public constant integer spiritlink = 852499
public constant integer spiritofvengeance = 852528
public constant integer spirittroll = 852573
public constant integer spiritwolf = 852126
public constant integer stampede = 852593
public constant integer standdown = 852113
public constant integer starfall = 852183
public constant integer stasistrap = 852114
public constant integer steal = 852574
public constant integer stomp = 852127
public constant integer stoneform = 852206
public constant integer stop = 851972
public constant integer submerge = 852604
public constant integer summonfactory = 852658
public constant integer summongrizzly = 852594
public constant integer summonphoenix = 852489
public constant integer summonquillbeast = 852595
public constant integer summonwareagle = 852596
public constant integer tankdroppilot = 852079
public constant integer tankloadpilot = 852080
public constant integer tankpilot = 852081
public constant integer taunt = 852520
public constant integer thunderbolt = 852095
public constant integer thunderclap = 852096
public constant integer tornado = 852597
public constant integer townbelloff = 852083
public constant integer townbellon = 852082
public constant integer tranquility = 852184
public constant integer unavatar = 852087
public constant integer unavengerform = 852532
public constant integer unbearform = 852139
public constant integer unburrow = 852534
public constant integer uncoldarrows = 852245
public constant integer uncorporealform = 852494
public constant integer undeadbuild = 851998
public constant integer undefend = 852056
public constant integer undivineshield = 852091
public constant integer unetherealform = 852497
public constant integer unflamingarrows = 852175
public constant integer unflamingattack = 852541
public constant integer unholyfrenzy = 852209
public constant integer unimmolation = 852178
public constant integer unload = 852047
public constant integer unloadall = 852048
public constant integer unloadallcorpses = 852054
public constant integer unloadallinstant = 852049
public constant integer unpoisonarrows = 852256
public constant integer unravenform = 852156
public constant integer unrobogoblin = 852657
public constant integer unroot = 852166
public constant integer unstableconcoction = 852500
public constant integer unstoneform = 852207
public constant integer unsubmerge = 852605
public constant integer unsummon = 852210
public constant integer unwindwalk = 852130
public constant integer vengeance = 852521
public constant integer vengeanceinstant = 852524
public constant integer vengeanceoff = 852523
public constant integer vengeanceon = 852522
public constant integer voodoo = 852503
public constant integer ward = 852504
public constant integer wardofshadowsight = 852570
public constant integer waterelemental = 852097
public constant integer wateryminion = 852598
public constant integer web = 852211
public constant integer weboff = 852213
public constant integer webon = 852212
public constant integer whirlwind = 852128
public constant integer windwalk = 852129
public constant integer wispharvest = 852214
public constant integer acidbomb = 852662
public constant integer chemicalrage = 852663
public constant integer healingspray = 852664
public constant integer transmute = 852665
public constant integer lavamonster = 852667
public constant integer soulburn = 852668
public constant integer volcano = 852669
public constant integer cancel = 851976
public constant integer moveslot1 = 852002
public constant integer moveslot2 = 852003
public constant integer moveslot3 = 852004
public constant integer moveslot4 = 852005
public constant integer moveslot5 = 852006
public constant integer moveslot6 = 852007
public constant integer useslot1 = 852008
public constant integer useslot2 = 852009
public constant integer useslot3 = 852010
public constant integer useslot4 = 852011
public constant integer useslot5 = 852012
public constant integer useslot6 = 852013
public constant integer smart = 851971
public constant integer skillmenu = 852000
endglobals
endlibrary
//TESH.scrollpos=28
//TESH.alwaysfold=0
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
// use the dummy.mdx model, so remember to import it as
// well, just use copy&paste to copy the dummy from the
// xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
// this rawcode to another spell that morphs into a flier
// in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
// raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
// timer that depends on it, if you put a low value
// the movement will look good but it may hurt your
// performance, if instead you use a high value it
// will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
// you got a unit bigger than 197.0 it would be
// a good idea to update this constant, since some
// enums will not find it. Likewise, if none of
// your units can go bellow X and X is much smaller
// than 197.0, it would be a good idea to update
// as well, since it will improve the performance
// those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************
//===========================================================================
globals
constant integer XE_DUMMY_UNITID = 'e000'
constant integer XE_HEIGHT_ENABLER = 'Amrf'
constant integer XE_TREE_RECOGNITION = 'Aeat'
constant real XE_ANIMATION_PERIOD = 0.025
constant real XE_MAX_COLLISION_SIZE = 197.0
endglobals
endlibrary
//TESH.scrollpos=39
//TESH.alwaysfold=0
library xepreload initializer init requires xebasic, optional TimerUtils
//******************************************************************************
// xepreload 0.8
// ---------
// Ah, the joy of preloading abilities, it is such a necessary evil...
// Notice you are not supposed to use this system in places outside map init
//
// This one does the preloading and tries to minimize the hit on loading time
// for example, it only needs one single native call per ability preloaded.
//
//******************************************************************************
//==============================================================================
globals
private unit dum=null
endglobals
private keyword DebugIdInteger2IdString
//inline friendly (when debug mode is off..)
function XE_PreloadAbility takes integer abilid returns nothing
call UnitAddAbility(dum, abilid)
static if DEBUG_MODE then
if(dum==null) then
call BJDebugMsg("XE_PreloadAbility: do not load abilities after map init or during structs' onInit")
elseif GetUnitAbilityLevel(dum, abilid) == 0 then
call BJDebugMsg("XE_PreloadAbility: Ability "+DebugIdInteger2IdString.evaluate(abilid)+" does not exist.")
endif
endif
endfunction
// ................................................................................
//================================================================================
// Convert a integer id value into a 4-letter id code.
// * Taken from cheats.j so I don't have to code it again.
// * Used only on debug so making a whole library for it seemed silly
// * Private so people don't begin using xepreload just to call this function....
// * It will not work correctly if you paste this code in the custom script section
// due to the infamous % bug. Then again, if you do that then you probably
// deserve it....
//
private function DebugIdInteger2IdString takes integer value returns string
local string charMap = ".................................!.#$%&'()*+,-./0123456789:;<=>.@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`abcdefghijklmnopqrstuvwxyz{|}~................................................................................................................................."
local string result = ""
local integer remainingValue = value
local integer charValue
local integer byteno
set byteno = 0
loop
set charValue = ModuloInteger(remainingValue, 256)
set remainingValue = remainingValue / 256
set result = SubString(charMap, charValue, charValue + 1) + result
set byteno = byteno + 1
exitwhen byteno == 4
endloop
return result
endfunction
//--------------------------------
private function kill takes nothing returns nothing
call RemoveUnit(dum)
set dum=null
static if (LIBRARY_TimerUtils ) then
call ReleaseTimer( GetExpiredTimer() )
else
call DestroyTimer(GetExpiredTimer())
endif
endfunction
private function init takes nothing returns nothing
local timer t
set dum = CreateUnit( Player(15), XE_DUMMY_UNITID, 0,0,0)
if( dum == null) then
debug call BJDebugMsg("xePreload : XE_DUMMY_UNITID ("+DebugIdInteger2IdString.evaluate(XE_DUMMY_UNITID)+") not added correctly to the map.")
endif
static if (LIBRARY_TimerUtils) then
set t=NewTimer()
else
set t=CreateTimer()
endif
call TimerStart(t,0.0,false,function kill)
set t=null
endfunction
endlibrary
//TESH.scrollpos=283
//TESH.alwaysfold=0
library xecast initializer init requires xebasic
//******************************************************************************
// xecast 0.7
// ------
// Because dummy casters REALLY ARE this complicated!
//
//******************************************************************************
//==============================================================================
globals
private constant integer MAXINSTANCES = 8190
//this is a lot, unless you leak xecast objects (which is a bad thing)
private constant integer INITIAL_DUMMY_COUNT = 12
//don't allow to keep more than DUMMY_STACK_LIMIT innactive dummy units :
private constant integer DUMMY_STACK_LIMIT = 50
// If your map does not give visibility to all players, or
// for other reasons, you might want xecast to work on
// units that are not visible to the player, in that case
// change this to true, else it is just a performance loss.
private constant boolean FORCE_INVISIBLE_CAST = false
//When AUTO_RESET_MANA_COOLDOWN is set to true, xecast will reset
// the dummy unit's cooldown and mana before casting every spell.
// it is a performance penalty, so if you are sure that all dummy spells
// in your map got 0 mana and cooldown cost, you may set it to false.
private constant boolean AUTO_RESET_MANA_COOLDOWN = true
endglobals
//=========================================================================
// Please notice all textmacros in this library are considered private.
// in other words: DON'T RUN THOSE TEXTMACROS!
//
private keyword structinit
globals
private real EPSILON=0.001 //noticed in war3 this is the sort of precision we want...
endglobals
struct xecast[MAXINSTANCES]
public integer abilityid = 0 //ID (rawcode) of the ability to cast
public integer level = 1 //Level of the ability to cast
public real recycledelay = 0.0 //Please notice, some spells need a recycle delay
// This is, a time period before they get recycle.
// For example, some spells are not instant, there is
// also the problem with damaging spells, this recycle
// delay must be large enough to contain all the time
// in which the spell can do damage.
public player owningplayer=Player(15) //which player to credit for the ability cast?
//notice this can also affect what units are targeteable
//==================================================================================================
// You need an order id for the ability so the dummy unit is able to cast it, two ways to assign it
// set instance.orderid = 288883 //would assign an integer orderid
// set instance.orderstring = "chainlightning" //would assign an orderstring
// (as those in the object editor)
//
method operator orderid= takes integer v returns nothing
set .oid=v
endmethod
method operator orderstring= takes string s returns nothing
set .oid=OrderId(s)
endmethod
//=================================================================================================
// Finally, you can determine from which point to cast the ability: z is the height coordinate.
//
public boolean customsource=false //Use a custom casting source?
public real sourcex // Determine the casting source for the dummy spell, require customsource =true
public real sourcey // You might prefer to use the setSourcePoint method
public real sourcez=0.0 //
method setSourcePoint takes real x, real y, real z returns nothing
set .sourcex=x
set .sourcey=y
set .sourcez=z
set .customsource=true
endmethod
method setSourceLoc takes location loc, real z returns nothing
set .sourcex=GetLocationX(loc)
set .sourcey=GetLocationY(loc)
set .sourcez=z
set .customsource=true
endmethod
private boolean autodestroy = false
//========================================================================================================
// you are always allowed to use .create() but you can also use createBasic which sets some things that
// are usually necessary up.
//
public static method createBasic takes integer abilityID, integer orderid, player owner returns xecast
local xecast r=xecast.allocate()
if(r==0) then
debug call BJDebugMsg("Warning: unbelievable but you actually used all xecast instances in your map! Please make sure you are not forgetting to destroy those what you create intensively, if that's not the case, then you'll have to increase xecast MAXINSTANCES")
endif
set r.oid=orderid
set r.abilityid=abilityID
set r.owningplayer=owner
return r
endmethod
//========================================================================================================
// Just like the above one, but the instance will self destruct after a call to any cast method
// (recommended)
//
public static method createBasicA takes integer abilityID, integer orderid, player owner returns xecast
local xecast r=xecast.allocate()
if(r==0) then
debug call BJDebugMsg("Warning: unbelievable but you actually used all xecast instances in your map! Please make sure you are not forgetting to destroy those what you create intensively, if that's not the case, then you'll have to increase xecast MAXINSTANCES")
endif
set r.oid=orderid
set r.abilityid=abilityID
set r.owningplayer=owner
set r.autodestroy=true
return r
endmethod
//==========================================================================================================
// Just like create, but the struct instance self destructs after a call to any cast method
// (Recommended)
//
public static method createA takes nothing returns xecast
local xecast r=xecast.allocate()
set r.autodestroy=true
return r
endmethod
//==========================================================================================================
// So, create the dummy, assign options and cast the skill!
// .castOnTarget(w) : If you want to hit a widget w with the ability
// .castOnPoint(x,y) : If you want to hit a point (x,y) with the ability
// .castInPoint(x,y) : For spells like warstomp which do not have a target.
// .castOnAOE(x,y,radius) : Classic area of effect cast. Considers collision size
// .castOnGroup(g) : Cast unit the unit group g, notice it will empty the group yet not destroy it.
//
//**********************************************************************************************************
// The implementation of such methods follows:
private static unit array dummystack
private static integer top=0
private static unit instantdummy
private integer oid=0
private static timer gametime
private static timer T
private static unit array recycle
private static real array expiretime
private static integer rn=0
//==========================================================================================================
// private dorecycle method, sorry but I need this up here.
//
private static method dorecycle takes nothing returns nothing
local unit u =.recycle[0]
local integer l
local integer r
local integer p
local real lt
call UnitRemoveAbility(u,GetUnitUserData(u))
call SetUnitUserData(u,0)
call SetUnitFlyHeight(u,0,0)
call PauseUnit(u,false)
if(.top==DUMMY_STACK_LIMIT) then
call RemoveUnit(u)
else
set .dummystack[.top]=u
set .top=.top+1
endif
set .rn=.rn-1
if(.rn==0) then
return
endif
set p=0
set lt=.expiretime[.rn]
loop
set l=p*2+1
exitwhen l>=.rn
set r=p*2+2
if(r>=.rn)then
if(.expiretime[l]<lt) then
set .expiretime[p]=.expiretime[l]
set .recycle[p]=.recycle[l]
set p=l
else
exitwhen true
endif
elseif (lt<=.expiretime[l]) and (lt<=.expiretime[r]) then
exitwhen true
elseif (.expiretime[l]<.expiretime[r]) then
set .expiretime[p]=.expiretime[l]
set .recycle[p]=.recycle[l]
set p=l
else
set .expiretime[p]=.expiretime[r]
set .recycle[p]=.recycle[r]
set p=r
endif
endloop
set .recycle[p]=.recycle[.rn]
set .expiretime[p]=lt
call TimerStart(.T, .expiretime[0]-TimerGetElapsed(.gametime), false, function xecast.dorecycle)
endmethod
private static trigger abilityRemove
// Repetitive process and no inline implemented for large functions, so for now it is a textmacro:
//! textmacro xecast_allocdummy
if(.recycledelay<EPSILON) then
set dummy=.instantdummy
call SetUnitOwner(dummy,.owningplayer,false)
elseif (.top>0) then
set .top=.top-1
set dummy=.dummystack[.top]
call SetUnitOwner(dummy,.owningplayer,false)
else
set dummy=CreateUnit(.owningplayer,XE_DUMMY_UNITID,0,0,0)
call TriggerRegisterUnitEvent(.abilityRemove,dummy,EVENT_UNIT_SPELL_ENDCAST)
call UnitAddAbility(dummy,'Aloc')
call UnitAddAbility(dummy,XE_HEIGHT_ENABLER)
call UnitRemoveAbility(dummy,XE_HEIGHT_ENABLER)
endif
call UnitAddAbility(dummy, abilityid)
static if AUTO_RESET_MANA_COOLDOWN then
call UnitResetCooldown(dummy)
call SetUnitState(dummy, UNIT_STATE_MANA, 10000.0)
endif
if(level>1) then
call SetUnitAbilityLevel(dummy, abilityid, level)
endif
//! endtextmacro
private static integer cparent
private static integer current
private static real cexpire
//! textmacro xecast_deallocdummy
if(.recycledelay>=EPSILON) then
set .cexpire=TimerGetElapsed(.gametime)+.recycledelay
set .current=.rn
set .rn=.rn+1
loop
exitwhen (.current==0)
set .cparent=(.current-1)/2
exitwhen (.expiretime[.cparent]<=.cexpire)
set .recycle[.current]=.recycle[.cparent]
set .expiretime[.current]=.expiretime[.cparent]
set .current=.cparent
endloop
set .expiretime[.current]=.cexpire
set .recycle[.current]=dummy
call SetUnitUserData(dummy,.abilityid)
call TimerStart(.T, .expiretime[0]-TimerGetElapsed(.gametime), false, function xecast.dorecycle)
else
call SetUnitUserData(dummy,0)
call SetUnitFlyHeight(dummy,0,0)
call UnitRemoveAbility(dummy,.abilityid)
endif
//! endtextmacro
method castOnTarget takes unit target, integer abilitylvl returns nothing
local unit dummy
local unit tar
//! runtextmacro xecast_allocdummy()
if (.customsource) then
call SetUnitX(dummy,.sourcex)
call SetUnitY(dummy,.sourcey)
call SetUnitFlyHeight(dummy,.sourcez,0.0)
else
call SetUnitX(dummy,GetWidgetX(target))
call SetUnitY(dummy,GetWidgetY(target))
endif
if (FORCE_INVISIBLE_CAST) then
call UnitShareVision(target, .owningplayer, true)
if abilitylvl != 0 then
call SetUnitAbilityLevel(dummy, .abilityid, abilitylvl)
endif
call IssueTargetOrderById(dummy,this.oid,target)
call UnitShareVision(target, .owningplayer, false)
else
call IssueTargetOrderById(dummy,this.oid,target)
endif
//! runtextmacro xecast_deallocdummy()
if(.autodestroy ) then
call this.destroy()
endif
endmethod
//accepts units, items and destructables, if you know it is
// a unit it is better to use castOnTarget since that would
// be able to use FORCE_INVISIBLE_CAST if necessary.
//
method castOnWidgetTarget takes widget target returns nothing
local unit dummy
local unit tar
//! runtextmacro xecast_allocdummy()
if (.customsource) then
call SetUnitX(dummy,.sourcex)
call SetUnitY(dummy,.sourcey)
call SetUnitFlyHeight(dummy,.sourcez,0.0)
else
call SetUnitX(dummy,GetWidgetX(target))
call SetUnitY(dummy,GetWidgetY(target))
endif
call IssueTargetOrderById(dummy,this.oid,target)
//! runtextmacro xecast_deallocdummy()
if(.autodestroy ) then
call this.destroy()
endif
endmethod
method castOnPoint takes real x, real y returns nothing
local unit dummy
//! runtextmacro xecast_allocdummy()
if (.customsource) then
call SetUnitX(dummy,.sourcex)
call SetUnitY(dummy,.sourcey)
call SetUnitFlyHeight(dummy,.sourcez,0.0)
else
call SetUnitX(dummy,x)
call SetUnitY(dummy,y)
endif
call IssuePointOrderById(dummy,this.oid,x,y)
//! runtextmacro xecast_deallocdummy()
if(.autodestroy ) then
call this.destroy()
endif
endmethod
method castOnLoc takes location loc returns nothing
//debug call BJDebugMsg("Warning: Locations are in use")
//nah but I should
call .castOnPoint(GetLocationX(loc),GetLocationY(loc))
endmethod
//ignores custom source x and y (for obvious reasons)
method castInPoint takes real x, real y returns nothing
local unit dummy
//! runtextmacro xecast_allocdummy()
if (.customsource) then
call SetUnitFlyHeight(dummy,.sourcez,0.0)
endif
call SetUnitX(dummy, x)
call SetUnitY(dummy, y)
call IssueImmediateOrderById(dummy,this.oid)
//! runtextmacro xecast_deallocdummy()
if(.autodestroy ) then
call this.destroy()
endif
endmethod
method castInLoc takes location loc returns nothing
//debug call BJDebugMsg("Warning: Locations are in use")
//nah but I should
call .castInPoint(GetLocationX(loc),GetLocationY(loc))
endmethod
//===================================================================================================
// For method castOnAOE:
//
private static group enumgroup
private static real aoex
private static real aoey
private static real aoeradius
private static xecast cinstance
private static boolexpr aoefunc
// Might look wrong, but this is the way to make it consider collision size, a spell that
// got a target circle and uses this method will let the user know which units it will
// hit with the mass cast.
static method filterAOE takes nothing returns boolean
local unit u=GetFilterUnit()
if IsUnitInRangeXY(u, .aoex, .aoey, .aoeradius) then
call .cinstance.castOnTarget(u, 0)
endif
set u=null
return false
endmethod
//
method castOnAOE takes real x, real y, real radius returns nothing
local boolean ad=this.autodestroy
if(ad) then
set this.autodestroy=false
endif
set .aoex=x
set .aoey=y
set .aoeradius=radius
set .cinstance=this
call GroupEnumUnitsInRange(.enumgroup,x,y,radius + XE_MAX_COLLISION_SIZE , .aoefunc)
if(ad) then
call this.destroy()
endif
endmethod
method castOnAOELoc takes location loc,real radius returns nothing
call .castOnAOE(GetLocationX(loc),GetLocationY(loc),radius)
endmethod
//==================================================================================================
// A quick and dirt castOnGroup method, perhaps it'll later have castOntarget inlined, but not now
//
method castOnGroup takes group g, integer lvl returns nothing
local boolean ad=this.autodestroy
local unit t
if(ad) then
set this.autodestroy=false
endif
loop
set t=FirstOfGroup(g)
exitwhen(t==null)
call GroupRemoveUnit(g,t)
call .castOnTarget(t, lvl)
endloop
if(ad) then
call this.destroy()
endif
endmethod
private static method removeAbility takes nothing returns boolean
local unit u=GetTriggerUnit()
if(GetUnitUserData(u)!=0) then
call PauseUnit(u,true)
endif
//This is necessary, picture a value for recycle delay that's higher than the casting time,
//for example if the spell does dps, if you leave the dummy caster with the ability and it
//is owned by an AI player it will start casting the ability on player units, so it is
// a good idea to pause it...
set u=null
return true
endmethod
//===================================================================================================
// structinit is a scope private keyword.
//
static method structinit takes nothing returns nothing
local integer i=INITIAL_DUMMY_COUNT+1
local unit u
set .aoefunc=Condition(function xecast.filterAOE)
set .enumgroup=CreateGroup()
set .abilityRemove = CreateTrigger()
loop
exitwhen (i==0)
set u=CreateUnit(Player(15),XE_DUMMY_UNITID,0,0,0)
call TriggerRegisterUnitEvent(.abilityRemove,u,EVENT_UNIT_SPELL_ENDCAST)
call UnitAddAbility(u,'Aloc')
call UnitAddAbility(u,XE_HEIGHT_ENABLER)
call UnitRemoveAbility(u,XE_HEIGHT_ENABLER)
set .dummystack[.top]=u
set .top=.top+1
set i=i-1
endloop
call TriggerAddCondition(.abilityRemove, Condition(function xecast.removeAbility ) )
set .top=.top-1
set .instantdummy=.dummystack[.top]
set .T=CreateTimer()
set .gametime=CreateTimer()
call TimerStart(.gametime,12*60*60,false,null)
endmethod
endstruct
private function init takes nothing returns nothing
call xecast.structinit()
endfunction
endlibrary