Name | Type | is_array | initial_value |
//TESH.scrollpos=36
//TESH.alwaysfold=0
library_once TimerUtils initializer redInit
//*********************************************************************
//* TimerUtils (Red flavor)
//* ----------
//*
//* 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.wc3campaigns.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.
//*
//* Red flavor: Fastest, method in existence for timer attaching,
//* only takes an array lookup, H2I and subtraction.
//* However, all the code in your map requires extra care
//* not to forget to call ReleaseTimer. It also requires
//* to preload a lot of timers at map init, they use
//* memory and handle ids.
//*
//* I recommend you run your map in debug mode the first
//* time after adding it, make sure you can see map init messages
//* if nothing appears, all is done, if an error appears, it might
//* suggest you a value with OFFSET, in that case, update that value
//* if it still does not work after updating (rare), try a bigger
//* OFFSET by 1000 for example. (Sounds hard? Then use blue or purple
//* timerutils that are friendlier though not as fast)
//*
//********************************************************************
//================================================================
globals
private constant integer OFFSET = 0x100000
private constant integer QUANTITY = 256
private constant integer ARRAY_SIZE = 8191 //changing this to a higher value would effectively
//cripple the performance making this thing irrelevant
endglobals
//=================================================================================================
private function H2I takes handle h returns integer
return GetHandleId( h )
endfunction
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
debug if(H2I(t)-OFFSET<0) then
debug call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
debug endif
set data[H2I(t)-OFFSET]=value
endfunction
function GetTimerData takes timer t returns integer
debug if(H2I(t)-OFFSET<0) then
debug call BJDebugMsg("GetTimerData: Wrong handle id, only use GetTimerData on timers created by NewTimer")
debug endif
return data[H2I(t)-OFFSET]
endfunction
//==========================================================================================
globals
private timer array tT
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, please increase it for your map, fix your map's timer leaks or switch to blue flavor when applicable")
set tT[0]=CreateTimer()
if (H2I(tT[0])-OFFSET<0) or (H2I(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably switch to the blue flavor or fix timer leaks.")
return null
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==8191) 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 redInit takes nothing returns nothing
local integer i=0
local integer bestoffset=-1
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set bestoffset=H2I(tT[i])
endif
if (H2I(tT[i])-OFFSET>=ARRAY_SIZE) then
debug call BJDebugMsg("TimerUtils_redInit: Failed a initializing attempt")
debug call BJDebugMsg("The timer limit is "+I2S(i))
debug call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low, to change OFFSET to "+I2S(bestoffset) )
exitwhen true
endif
if (H2I(tT[i])-OFFSET>=0) then
set i=i+1
endif
endloop
set tN=i
endfunction
endlibrary
//TESH.scrollpos=44
//TESH.alwaysfold=0
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
globals
// High enough so the unit is no longer visible, low enough so the
// game doesn't crash...
//
// I think you need 0.0 or soemthing negative prior to patch 1.22
//
private constant real EXTRA = 500.0
endglobals
//=========================================================================================
globals
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns nothing
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
endfunction
private function init takes nothing returns nothing
local trigger t=CreateTrigger()
local region r=CreateRegion()
local rect rc
set minx=GetCameraBoundMinX() - EXTRA
set miny=GetCameraBoundMinY() - EXTRA
set maxx=GetCameraBoundMaxX() + EXTRA
set maxy=GetCameraBoundMaxY() + EXTRA
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddAction(t, function dis)
//this is not necessary but I'll do it anyway:
set t=null
set r=null
set rc=null
endfunction
endlibrary
//TESH.scrollpos=266
//TESH.alwaysfold=0
library VectorLib
globals
private location loc = Location(0.0,0.0)
endglobals
struct vector
real x
real y
real z
static method create takes real x, real y, real z returns vector
local vector v = vector.allocate()
set v.x=x
set v.y=y
set v.z=z
return v
endmethod
method getLength takes nothing returns real
return SquareRoot(.x*.x + .y*.y + .z*.z)
endmethod
static method sum takes vector augend, vector addend returns vector
local vector v = vector.allocate()
set v.x = augend.x+addend.x
set v.y = augend.y+addend.y
set v.z = augend.z+addend.z
return v
endmethod
method add takes vector addend returns nothing
set this.x=this.x+addend.x
set this.y=this.y+addend.y
set this.z=this.z+addend.z
endmethod
static method difference takes vector minuend, vector subtrahend returns vector
local vector v = vector.allocate()
set v.x = minuend.x-subtrahend.x
set v.y = minuend.y-subtrahend.y
set v.z = minuend.z-subtrahend.z
return v
endmethod
method subtract takes vector subtrahend returns nothing
set this.x=this.x-subtrahend.x
set this.y=this.y-subtrahend.y
set this.z=this.z-subtrahend.z
endmethod
method scale takes real factor returns nothing
set this.x=this.x*factor
set this.y=this.y*factor
set this.z=this.z*factor
endmethod
method setLength takes real length returns nothing
local real l = SquareRoot(.x*.x + .y*.y + .z*.z)
if l == 0.0 then
debug call BJDebugMsg("Attempted to set the length of a vector with no length!")
return
endif
set l = length/l
set this.x = this.x*l
set this.y = this.y*l
set this.z = this.z*l
endmethod
static method dotProduct takes vector a, vector b returns real
return (a.x*b.x+a.y*b.y+a.z*b.z)
endmethod
static method crossProduct takes vector a, vector b returns vector
local vector v = vector.allocate()
set v.x = a.y*b.z - a.z*b.y
set v.y = a.z*b.x - a.x*b.z
set v.z = a.x*b.y - a.y*b.x
return v
endmethod
static method projectionVector takes vector projected, vector direction returns vector
local vector v = vector.allocate()
local real l = direction.x*direction.x+direction.y*direction.y+direction.z*direction.z
if l == 0.0 then
call v.destroy()
debug call BJDebugMsg("Attempted to project onto a vector with no length!")
return null
endif
set l = (projected.x*direction.x+projected.y*direction.y+projected.z*direction.z) / l
set v.x = direction.x*l
set v.y = direction.y*l
set v.z = direction.z*l
return v
endmethod
method projectVector takes vector direction returns nothing
local real l = direction.x*direction.x+direction.y*direction.y+direction.z*direction.z
if l == 0.0 then
debug call BJDebugMsg("Attempted to project onto a vector with no length!")
return
endif
set l = (this.x*direction.x+this.y*direction.y+this.z*direction.z) / l
set this.x = direction.x*l
set this.y = direction.y*l
set this.z = direction.z*l
endmethod
static method projectionPlane takes vector projected, vector normal returns vector
local vector v = vector.allocate()
local real l = normal.x*normal.x+normal.y*normal.y+normal.z*normal.z
if l == 0.0 then
call v.destroy()
debug call BJDebugMsg("Attempted to project onto an undefined plane!")
return null
endif
set l = (projected.x*normal.x+projected.y*normal.y+projected.z*normal.z) / l
set v.x = projected.x - normal.x*l
set v.y = projected.y - normal.y*l
set v.z = projected.z - normal.z*l
return v
endmethod
method projectPlane takes vector normal returns nothing
local real l = normal.x*normal.x+normal.y*normal.y+normal.z*normal.z
if l == 0.0 then
debug call BJDebugMsg("Attempted to project onto an undefined plane!")
return
endif
set l = (this.x*normal.x+this.y*normal.y+this.z*normal.z) / l
set this.x = this.x - normal.x*l
set this.y = this.y - normal.y*l
set this.z = this.z - normal.z*l
endmethod
static method getAngle takes vector a, vector b returns real
local real l = SquareRoot(a.x*a.x + a.y*a.y + a.z*a.z)*SquareRoot(b.x*b.x + b.y*b.y + b.z*b.z)
if l == 0 then
debug call BJDebugMsg("Attempted to get angle between vectors with no length!")
return 0.0
endif
return Acos((a.x*b.x+a.y*b.y+a.z*b.z)/l) //angle is returned in radians
endmethod
method rotate takes vector axis, real angle returns nothing //angle is taken in radians
local real xx
local real xy
local real xz
local real yx
local real yy
local real yz
local real zx
local real zy
local real zz
local real al = axis.x*axis.x+axis.y*axis.y+axis.z*axis.z //axis length^2
local real f
local real c = Cos(angle)
local real s = Sin(angle)
if al == 0.0 then
debug call BJDebugMsg("Attempted to project onto a vector with no length!")
return
endif
set f = (this.x*axis.x+this.y*axis.y+this.z*axis.z) / al
set zx = axis.x*f
set zy = axis.y*f
set zz = axis.z*f //axis component of rotated vector
set xx = this.x-zx
set xy = this.y-zy
set xz = this.z-zz //component of vector perpendicular to axis
set al = SquareRoot(al)
set yx = (axis.y*xz - axis.z*xy)/al
set yy = (axis.z*xx - axis.x*xz)/al //y same length as x by using cross product and dividing with axis length
set yz = (axis.x*xy - axis.y*xx)/al //x,y - coordinate system in which we rotate
set this.x=xx*c+yx*s+zx
set this.y=xy*c+yy*s+zy
set this.z=xz*c+yz*s+zz
endmethod
static method createTerrainPoint takes real x, real y returns vector
local vector v = vector.allocate()
call MoveLocation(loc,x,y)
set v.x=x
set v.y=y
set v.z=GetLocationZ(loc)
return v
endmethod
method getTerrainPoint takes real x, real y returns nothing
call MoveLocation(loc,x,y)
set this.x=x
set this.y=y
set this.z=GetLocationZ(loc)
endmethod
static method createTerrainNormal takes real x, real y, real sampleRadius returns vector
local vector v = vector.allocate()
local real z1
local real z2
local real z3
local real z4
call MoveLocation(loc, x-sampleRadius, y)
set z1=GetLocationZ(loc)
call MoveLocation(loc, x+sampleRadius, y)
set z2=GetLocationZ(loc)
call MoveLocation(loc, x, y-sampleRadius)
set z3=GetLocationZ(loc)
call MoveLocation(loc, x, y+sampleRadius)
set z4=GetLocationZ(loc)
set sampleRadius=2*sampleRadius
set v.x = (z1-z2)*sampleRadius
set v.y = (z3-z4)*sampleRadius
set v.z = sampleRadius*sampleRadius
return v
endmethod
method getTerrainNormal takes real x, real y, real sampleRadius returns nothing
local real z1
local real z2
local real z3
local real z4
call MoveLocation(loc, x-sampleRadius, y)
set z1=GetLocationZ(loc)
call MoveLocation(loc, x+sampleRadius, y)
set z2=GetLocationZ(loc)
call MoveLocation(loc, x, y-sampleRadius)
set z3=GetLocationZ(loc)
call MoveLocation(loc, x, y+sampleRadius)
set z4=GetLocationZ(loc)
set sampleRadius=2*sampleRadius
set this.x = (z1-z2)*sampleRadius
set this.y = (z3-z4)*sampleRadius
set this.z = sampleRadius*sampleRadius
endmethod
method isInCylinder takes vector cylinderOrigin, vector cylinderHeight, real cylinderRadius returns boolean
local real l
local real x = this.x-cylinderOrigin.x
local real y = this.y-cylinderOrigin.y
local real z = this.z-cylinderOrigin.z
if x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z < 0.0 then //point below cylinder
return false
endif
set x = x-cylinderHeight.x
set y = y-cylinderHeight.y
set z = z-cylinderHeight.z
if x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z > 0.0 then //point above cylinder
return false
endif
set l = cylinderHeight.x*cylinderHeight.x+cylinderHeight.y*cylinderHeight.y+cylinderHeight.z*cylinderHeight.z
if l == 0.0 then
debug call BJDebugMsg("Cylinder with no height!")
return false
endif
set l = (x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z) / l
set x = x - cylinderHeight.x*l
set y = y - cylinderHeight.y*l
set z = z - cylinderHeight.z*l
if x*x+y*y+z*z > cylinderRadius*cylinderRadius then //point outside cylinder
return false
endif
return true
endmethod
method isInCone takes vector coneOrigin, vector coneHeight, real coneRadius returns boolean
local real l
local real x = this.x-coneOrigin.x
local real y = this.y-coneOrigin.y
local real z = this.z-coneOrigin.z
if x*coneHeight.x+y*coneHeight.y+z*coneHeight.z < 0.0 then //point below cone
return false
endif
set l = coneHeight.x*coneHeight.x+coneHeight.y*coneHeight.y+coneHeight.z*coneHeight.z
if l == 0.0 then
debug call BJDebugMsg("cone with no height!")
return false
endif
set l = (x*coneHeight.x+y*coneHeight.y+z*coneHeight.z) / l
set x = x - coneHeight.x*l
set y = y - coneHeight.y*l
set z = z - coneHeight.z*l
if SquareRoot(x*x+y*y+z*z) > coneRadius*(1.0-l) then //point outside cone
return false
endif
return true
endmethod
method isInSphere takes vector sphereOrigin, real sphereRadius returns boolean
if sphereRadius*sphereRadius < ((this.x-sphereOrigin.x)*(this.x-sphereOrigin.x)+(this.y-sphereOrigin.y)*(this.y-sphereOrigin.y)+(this.z-sphereOrigin.z)*(this.z-sphereOrigin.z)) then
return false
endif
return true
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Heights
globals
private location loc = Location( 0.00, 0.00 )
endglobals
function GetFloorHeight takes real x, real y returns real
call MoveLocation( loc, x, y )
return GetLocationZ( loc )
endfunction
function GetUnitZ takes unit whichUnit returns real
local real z = ( GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ) + GetUnitFlyHeight( whichUnit ) )
set whichUnit = null
return z
endfunction
function SetUnitZ takes unit whichUnit, real z returns nothing
local boolean whichUnitHasNotAmrf = ( GetUnitAbilityLevel( whichUnit, 'Amrf' ) <= 0 ) and IsUnitType(whichUnit, UNIT_TYPE_FLYING) == false
if ( whichUnitHasNotAmrf ) then
call UnitAddAbility( whichUnit, 'Amrf' )
endif
call SetUnitFlyHeight( whichUnit, z - GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ), 0.00 )
if ( whichUnitHasNotAmrf ) then
call UnitRemoveAbility( whichUnit, 'Amrf' )
endif
set whichUnit = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope BurningOrbit initializer init
//*************************************************************************************************************//
// Burning Orbit //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// Vector lib by //
// Heights by cedi //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
globals
//ID of the dummy spell
private constant integer SPELL_ID = 'A000'
//ID of the spell which the splits should have. Beware, only unit target spells or passivs.
private constant integer SPLIT_SPELL = 'A001'
//ID of the spell which they mmain orb should have. BEware, only passivs.
private constant integer MAIN_SPELL = '0000'
//ID of the dummy
private constant integer DUMMY_ID = 'h000'
//How many levels does your spell have?
private constant integer SPELL_LEVEL_COUNT = 4
//How many splits do you want?
private constant integer MAX_SPLITS = 20
//How many moves should the spreed out use?
private constant integer MOVES = 25
//Red part of the color of the main orb ( 0 - 255 )
private constant integer COLOR_RED = 255
//Green part of the color of the main orb ( 0 - 255 )
private constant integer COLOR_GREEN = 255
//Blue part of the color of the main orb ( 0 - 255 )
private constant integer COLOR_BLUE = 255
//Alpha part of the color of the main orb ( 0 - 255 )
private constant integer COLOR_ALPHA = 255
//Red part of the color of the split orb ( 0 - 255 )
private constant integer SPLIT_COLOR_RED = 255
//Green part of the color of the split orb ( 0 - 255 )
private constant integer SPLIT_COLOR_GREEN = 255
//Blue part of the color of the split orb ( 0 - 255 )
private constant integer SPLIT_COLOR_BLUE = 255
//Alpha part of the color of the split orb ( 0 - 255 )
private constant integer SPLIT_COLOR_ALPHA = 255
//The move timer interval
private constant real TIMER_INTERVAL = 0.02
//Max distance of the splits to the main orb.
private constant real MAX_DISTANCE = 300.00
//Min distance of the splits to the main orb.
private constant real MIN_DISTANCE = 100.00
//Max rotation speed of the splits in grad.
private constant real MAX_SPEED = 2.00
//Min rotation speed of the splits in grad.
private constant real MIN_SPEED = 0.50
//Flyheight of the main orb.
private constant real MAIN_FLY_HEIGHT = 500.00
//Maximal cooldown add.
private constant real MAX_COOLDOWN_ADD = 3.00
//Delay between summon and split.
private constant real SPLIT_DELAY = 3.00
//Size of the main orb 1 == 100% size.
private constant real MAIN_SIZE = 3.00
//Size of the splits orb 1 == 100% size.
private constant real SPLIT_SIZE = 1.00
//Model of the splits.
private constant string SPLIT_MODEL = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl"
//Model of the main orb.
private constant string MAIN_MODEL = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl"
//Effect when the main orb split up.
private constant string SPLIT_EFFECT = "Abilities\\Spells\\Orc\\FeralSpirit\\feralspiritdone.mdl"
//Effect when the main orb comes to gether.
private constant string SPLIT_END_EFFECT = ""
//Order string of the split spell.
private constant string ORDER_STRING = "acidbomb"
//Effect when the main orb appears.
private constant string CREATE_EFFECT = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
//Effect when the main orb disappears.
private constant string REMOVE_EFFECT = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
//Should the main orb get invisible during splitting?
private constant boolean HIDE_MAIN = true
//Is the split spell targeting enemies?
private constant boolean TARGET_ENEMY = true
//Should the splits fly around on 3d?
private constant boolean 3D = true
private vector AXISZ //System
private vector AXISX //System
private vector AXISY //System
private vector TEMPVECTOR2 //System
private real array COOLDOWN //System
private real array DURATION //System
private real array AOE //System
private group TEMPGROUP = CreateGroup() //System
endglobals
//Cooldown of the split spell.
private function SET_COOLDOWN takes nothing returns nothing
set COOLDOWN[1] = 3.00
set COOLDOWN[2] = 3.00
set COOLDOWN[3] = 3.00
set COOLDOWN[4] = 3.00
endfunction
//Duration of the whole spell
private function SET_DURATION takes nothing returns nothing
set DURATION[1] = 12.00
set DURATION[2] = 12.00
set DURATION[3] = 12.00
set DURATION[4] = 12.00
endfunction
//Range of the dummy spell ( the value in the oe should be bigger then this )
private function SET_AOE takes nothing returns nothing
set AOE[1] = 550.00
set AOE[2] = 550.00
set AOE[3] = 550.00
set AOE[4] = 550.00
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private keyword SF_Split
private keyword SF_Main
private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
private struct SF_Split
unit split
integer movescounter = 0
real angleZ
real angleX
real angleY
real cd = 0.00
real nextcast = 0.00
boolean reachedLoc = false
boolean goinInit = false
effect sfx
SF_Main root
vector posi
vector tmpposi
vector move
method onDestroy takes nothing returns nothing
call DestroyEffect( .sfx )
call KillUnit( .split )
set .sfx = null
set .split = null
call .posi.destroy()
call .move.destroy()
endmethod
private method GetRandomNextCast takes nothing returns nothing
set .nextcast = COOLDOWN[.root.level] + GetRandomReal( 0.00, MAX_COOLDOWN_ADD )
endmethod
private method Cast takes nothing returns nothing
local unit u
call .GetRandomNextCast()
set .cd = 0.00
call GroupEnumUnitsInRange( TEMPGROUP, GetUnitX( .split ), GetUnitY( .split ), AOE[.root.level], Condition( function IsAliveAndUnitAndNotMagicImmune ) )
loop
set u = FirstOfGroup( TEMPGROUP )
exitwhen u == null
if IsUnitEnemy( u, .root.owner ) == TARGET_ENEMY then
call IssueTargetOrder( .split, ORDER_STRING, u )
set u = null
call GroupClear( TEMPGROUP )
exitwhen true
endif
call GroupRemoveUnit( TEMPGROUP, u )
endloop
endmethod
private method Zangle takes real z returns nothing
local integer i=R2I(z*bj_RADTODEG+90.5)
if(i>=180) then
set i=179
elseif(i<0) then
set i=0
endif
call SetUnitAnimationByIndex(.split, i )
endmethod
private method Turn takes nothing returns nothing
local real z = .posi.z
local real x = .posi.x
local real y = .posi.y
call .posi.rotate( AXISZ, .angleZ )
set x = ( .root.posi.x + .posi.x ) - ( .root.posi.x + x )
set y = ( .root.posi.y + .posi.y ) - ( .root.posi.y + y )
if 3D == true then
call .posi.rotate( AXISX, .angleX )
call .posi.rotate( AXISY, .angleY )
set z = ( .root.posi.z + .posi.z ) - ( .root.posi.z + z )
call .Zangle( Atan(( z / (SquareRoot(x*x + y*y))) ) )
call SetUnitZ( .split, .root.posi.z + .posi.z )
endif
call SetUnitX( .split, .root.posi.x + .posi.x )
call SetUnitY( .split, .root.posi.y + .posi.y )
call SetUnitFacing(.split,Atan2(y, x)*bj_RADTODEG)
endmethod
private method SetPositonReturn takes nothing returns nothing
if .movescounter <= MOVES then
call .tmpposi.add( .move )
call SetUnitX( .split, .tmpposi.x )
call SetUnitY( .split, .tmpposi.y )
call SetUnitZ( .split, .tmpposi.z )
else
call .destroy()
endif
set .movescounter = .movescounter + 1
endmethod
private method SetPositon takes nothing returns nothing
if .movescounter <= MOVES then
call .tmpposi.add( .move )
call SetUnitX( .split, .tmpposi.x )
call SetUnitY( .split, .tmpposi.y )
call SetUnitZ( .split, .tmpposi.z )
else
set .reachedLoc = true
endif
set .movescounter = .movescounter + 1
endmethod
method control takes nothing returns nothing
if .root.splitlifetime <= 0.00 then
call .destroy()
endif
if .root.goin == true then
if .goinInit == false then
set .movescounter = 0
set .goinInit = true
set .tmpposi.x = .root.posi.x + .posi.x
set .tmpposi.y = .root.posi.y + .posi.y
set .tmpposi.z = .root.posi.z + .posi.z
set .move.x = ( .posi.x * -1.00 ) / I2R( MOVES )
set .move.y = ( .posi.y * -1.00 ) / I2R( MOVES )
set .move.z = ( .posi.z * -1.00 ) / I2R( MOVES )
set .movescounter = 0
endif
call .SetPositonReturn()
endif
if .reachedLoc == false then
call .SetPositon()
elseif .root.goin == false then
call .Turn()
set .cd = .cd + TIMER_INTERVAL
if .cd >= .nextcast then
call .Cast()
endif
endif
endmethod
private method GetRamdomAngle takes nothing returns nothing
local integer i = GetRandomInt( 0, 1 )
local real r = GetRandomReal( MIN_SPEED, MAX_SPEED ) * bj_DEGTORAD
if i == 0 then
set .angleZ = r * -1
else
set .angleZ = r
endif
set i = GetRandomInt( 0, 1 )
set r = GetRandomReal( MIN_SPEED, MAX_SPEED ) * bj_DEGTORAD
if i == 0 then
set .angleX = r * -1
else
set .angleX = r
endif
set i = GetRandomInt( 0, 1 )
set r = GetRandomReal( MIN_SPEED, MAX_SPEED ) * bj_DEGTORAD
if i == 0 then
set .angleY = r * -1
else
set .angleY = r
endif
endmethod
private method GetRandomPosi takes nothing returns nothing
local real a = GetRandomReal( 0.00, 360.00 ) * bj_DEGTORAD
local real b = GetRandomReal( 0.00, 180.00 ) * bj_DEGTORAD
local real r = GetRandomReal( MIN_DISTANCE, MAX_DISTANCE )
local real times = I2R( MOVES )
set .posi = vector.create( r*Cos(a)*Cos(b), r*Cos(a)*Sin(b), r*Sin(a) )
set .move = vector.create( .posi.x / times , .posi.y / times, .posi.z / times )
endmethod
static method create takes SF_Main root returns SF_Split
local SF_Split data = SF_Split.allocate()
set data.root = root
call data.GetRandomPosi()
call data.GetRamdomAngle()
set data.split = CreateUnit( root.owner, DUMMY_ID, 0.00, 0.00, GetRandomReal( 0.00, 360.00 ) )
set data.sfx = AddSpecialEffectTarget( SPLIT_MODEL, data.split, "origin" )
call data.GetRandomNextCast()
call UnitAddAbility( data.split, SPLIT_SPELL )
call SetUnitAbilityLevel( data.split, SPLIT_SPELL, data.root.level )
call data.SetPositon()
call SetUnitVertexColor( data.split, SPLIT_COLOR_RED, SPLIT_COLOR_GREEN, SPLIT_COLOR_BLUE, SPLIT_COLOR_ALPHA )
call SetUnitScale( data.split, SPLIT_SIZE, SPLIT_SIZE, SPLIT_SIZE )
set data.tmpposi = vector.create( root.posi.x, root.posi.y, root.posi.z )
return data
endmethod
endstruct
private function Control takes nothing returns nothing
local timer t = GetExpiredTimer()
local SF_Main data = GetTimerData( t )
call data.control()
set t = null
endfunction
private struct SF_Main
unit main = null
unit caster = null
integer level = 1
timer t = null
player owner = null
boolean goin = false
boolean splitupdone = false
boolean end = false
boolean moving = false
real splitlifetime
real delay = SPLIT_DELAY
effect sfx = null
SF_Main data = 0
SF_Split array splits[MAX_SPLITS]
vector posi = 0
vector move = 0
method control takes nothing returns nothing
local integer i = 0
if .splitupdone == false then
set .delay = .delay - TIMER_INTERVAL
if .delay <= 0.00 then
set .splitupdone = true
call DestroyEffect( AddSpecialEffectTarget( SPLIT_EFFECT, .main, "origin" ) )
if HIDE_MAIN then
call SetUnitVertexColor( .main, 255, 255, 255, 0 )
endif
loop
exitwhen i == MAX_SPLITS
set .splits[i] = SF_Split.create( .data )
set i = i + 1
endloop
endif
endif
if .splitlifetime <= 0.00 and .end == false then
set .delay = SPLIT_DELAY
set .end = true
if HIDE_MAIN then
call SetUnitVertexColor( .main, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_ALPHA )
call DestroyEffect( AddSpecialEffectTarget( SPLIT_END_EFFECT, .main, "origin" ) )
set i = 0
loop
exitwhen i == MAX_SPLITS
if .splits[i] != 0 then
call .splits[i].control()
endif
set i = i + 1
endloop
endif
endif
if .end == true then
set .delay = .delay - TIMER_INTERVAL
if .delay <= 0.00 then
call DestroyEffect( AddSpecialEffectTarget( REMOVE_EFFECT, .main, "origin" ) )
call .destroy()
endif
endif
if .moving then
call .posi.add( .move )
call SetUnitX( .main, .posi.x )
call SetUnitY( .main, .posi.y )
endif
if .splitlifetime <= I2R( MOVES ) * TIMER_INTERVAL and .goin == false then
set .goin = true
endif
set i = 0
if .splitupdone and not .end then
set .splitlifetime = .splitlifetime - TIMER_INTERVAL
loop
exitwhen i == MAX_SPLITS
if .splits[i] != 0 then
call .splits[i].control()
endif
set i = i + 1
endloop
endif
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer( .t )
call DestroyEffect( .sfx )
call KillUnit( .main )
call .posi.destroy()
if .moving == true then
call .move.destroy()
endif
endmethod
static method create takes unit caster, real x, real y, vector move returns SF_Main
local SF_Main data = SF_Main.allocate()
set data.data = data
set data.t = NewTimer()
call SetTimerData( data.t, data )
set data.caster = caster
set data.owner = GetOwningPlayer( caster )
set data.main = CreateUnit( data.owner, DUMMY_ID, x, y, GetRandomReal( 0.00, 360.00 ) )
set data.sfx = AddSpecialEffectTarget( MAIN_MODEL, data.main, "origin" )
set data.level = GetUnitAbilityLevel( caster, SPELL_ID )
set data.splitlifetime = DURATION[data.level]
call SetUnitFlyHeight( data.main, MAIN_FLY_HEIGHT, 0.00 )
call DestroyEffect( AddSpecialEffectTarget( CREATE_EFFECT, data.main, "origin" ) )
call UnitAddAbility( data.main, MAIN_SPELL )
call SetUnitAbilityLevel( data.main, MAIN_SPELL, data.level )
call SetUnitVertexColor( data.main, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_ALPHA )
call SetUnitScale( data.main, MAIN_SIZE, MAIN_SIZE, MAIN_SIZE )
if move != 0 then
set data.move = move
set data.moving = true
endif
set data.posi = vector.create( x, y, GetUnitZ( data.main ) )
call TimerStart( data.t, TIMER_INTERVAL, true, function Control )
set caster = null
return data
endmethod
endstruct
private function IsSpell takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call SF_Main.create( GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY(), 0 )
endif
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function IsSpell ) )
set AXISX = vector.create( 1.00, 0.00, 0.00 )
set AXISY = vector.create( 0.00, 1.00, 0.00 )
set AXISZ = vector.create( 0.00, 0.00, 1.00 )
set TEMPVECTOR2 = vector.create( 0.00, 0.00, 0.00 )
call SET_COOLDOWN()
call SET_DURATION()
call SET_AOE()
set t = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Revive_Units_Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == false
endfunction
function Trig_Revive_Units_Actions takes nothing returns nothing
call TriggerSleepAction( 10.00 )
call CreateUnit( GetOwningPlayer( GetTriggerUnit() ), GetUnitTypeId( GetTriggerUnit() ), GetUnitX( GetTriggerUnit() ), GetUnitY( GetTriggerUnit() ), GetUnitFacing( GetTriggerUnit() ) )
endfunction
//===========================================================================
function InitTrig_Revive_Units takes nothing returns nothing
set gg_trg_Revive_Units = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Revive_Units, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Revive_Units, Condition( function Trig_Revive_Units_Conditions ) )
call TriggerAddAction( gg_trg_Revive_Units, function Trig_Revive_Units_Actions )
endfunction