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=23
//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
//*************************************************************************************************************//
// Sparkling Bolt v0.02 //
// 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.
private keyword Bolt
private keyword Spark
globals
//ID of the spell
private constant integer SPELL_ID = 'A000'
//ID of your dummy
private constant integer DUMMY_ID = 'h000'
//Interval of the moves
private constant real TIMER_INTERVAL = 0.035
//The normal gravity ( change to adjust the drop speed )
private constant real GRAVITY = 9.81
//BOLT
//Color of the bolt in rgb
private constant integer BOLT_RED = 255
private constant integer BOLT_GREEN = 255
private constant integer BOLT_BLUE = 255
private constant integer BOLT_ALPHA = 255
//Speed of the bolt in wc3 units
private constant real BOLT_SPEED = 500.00
//Shoot angle like the one in the oe
private constant real BOLT_HEIGHT = 0.45
//Size of the bolt
private constant real BOLT_SIZE = 4.00
//Collisions range of the bolt
private constant real BOLT_COL_RANGE = 20.00 //Collisionsrange
//Model of the bolt
private constant string BOLT_MODEL = "Abilities\\Weapons\\VengeanceMissile\\VengeanceMissile.mdl"
//Effect on hit
private constant string BOLT_HIT_SFX = ""
//SPARK
//Color of the spark in rgb
private constant integer SPARK_RED = 255
private constant integer SPARK_GREEN = 255
private constant integer SPARK_BLUE = 255
private constant integer SPARK_ALPHA = 255
private constant integer SPARK_COUNT_PER_CD = 2
//Start speed of the sparks in wc3 units
private constant real SPARK_SPEED = 250.00
//Size of the sparks
private constant real SPARK_SIZE = 0.5
//Each ... seconds create a spark
private constant real SPARK_CD = 0.10
//Speed lose of the speed gain through the movement of the bolt
private constant real SPARK_SPEED_LOSE = 0.04
//Sparks model
private constant string SPARK_MODEL = "Abilities\\Weapons\\SerpentWardMissile\\SerpentWardMissile.mdl"
//Effect when the sparks hit the ground.
private constant string SPARK_HIT_SFX = ""
//private constant string SPARK_SPELL_ORDER = ""
//SYSTEM
private vector G
private vector TEMPVEC
private Bolt TEMPBOLT
private Spark TEMPSPARK
private group GROUP = CreateGroup()
endglobals
private function BOLT_DAMAGE takes integer level returns real
return 100.00 + 50.00 * level
endfunction
private function SPARK_DAMAGE takes integer level returns real
return 20.00 + 10.00 * level
endfunction
private function SPARK_AOE takes integer level returns real
return 70.00 + 5.00 * level
endfunction
private function BOLT_AOE takes integer level returns real
return 125.00 + 25.00 * level
endfunction
private function BOLT_AOE_DAMAGE takes integer level returns real
return 50.00 + 25.00 * level
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private function AngleBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
private function DistanceBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
private function AngleBetweenUnits takes unit u, unit u2 returns real
return bj_RADTODEG * Atan2(GetUnitY( u2 ) - GetUnitY( u ), GetUnitX( u2 ) - GetUnitX( u ))
endfunction
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 function ParabolaZ2 takes real y0, real y1, real h, real d, real x returns real
local real A = (2*(y0+y1)-4*h)/(d*d)
local real B = (y1-y0-A*d*d)/d
return A*x*x + B*x + y0
endfunction
private function BoltControl takes nothing returns nothing
set TEMPBOLT = GetTimerData( GetExpiredTimer() )
call TEMPBOLT.control()
endfunction
private function SparkControl takes nothing returns nothing
set TEMPSPARK = GetTimerData( GetExpiredTimer() )
call TEMPSPARK.control()
endfunction
private struct Spark
unit spark
unit caster
vector startspeed
vector boltspeed
vector posi
timer t
effect model
integer level
method onDestroy takes nothing returns nothing
local unit u
call GroupEnumUnitsInRange( GROUP, .posi.x, .posi.y, SPARK_AOE( .level ), function IsAliveAndUnitAndNotMagicImmune )
loop
set u = FirstOfGroup( GROUP )
exitwhen u == null
if IsUnitEnemy( u, GetOwningPlayer( .spark ) ) then
call UnitDamageTarget( .caster, u, SPARK_DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
endif
call GroupRemoveUnit( GROUP, u )
set u = null
endloop
call DestroyEffect( AddSpecialEffect( SPARK_HIT_SFX, .posi.x, .posi.y ) )
call .startspeed.destroy()
call .boltspeed.destroy()
call .posi.destroy()
call ReleaseTimer( .t )
set .t = null
call DestroyEffect( .model )
set .model = null
call KillUnit( .spark )
set .spark = null
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( .spark, i )
endmethod
method control takes nothing returns nothing
local real z
local real x
local real y
if GetWidgetLife( .spark ) <= 0.405 then
call .destroy()
return
endif
//Gravity
call .startspeed.subtract( G )
//boltspeed
set .boltspeed.x = .boltspeed.x * ( 1.00 - SPARK_SPEED_LOSE )
set .boltspeed.y = .boltspeed.y * ( 1.00 - SPARK_SPEED_LOSE )
set .boltspeed.z = .boltspeed.z * ( 1.00 - SPARK_SPEED_LOSE )
//Calc
set TEMPVEC.x = .posi.x
set TEMPVEC.y = .posi.y
set TEMPVEC.z = .posi.z
call TEMPVEC.add( .startspeed )
call TEMPVEC.add( .boltspeed )
//dif
set x = TEMPVEC.x - .posi.x
set y = TEMPVEC.y - .posi.y
set z = TEMPVEC.z - .posi.z
//Zangle
call .Zangle( Atan(( z / (SquareRoot(x*x + y*y))) ) )
//Unit facing
call SetUnitFacing( .spark, AngleBetweenCoordinates( .posi.x, TEMPVEC.x, .posi.y, TEMPVEC.y ) )
//new posi
set .posi.x = TEMPVEC.x
set .posi.y = TEMPVEC.y
set .posi.z = TEMPVEC.z
//move there
call SetUnitX( .spark, .posi.x )
call SetUnitY( .spark, .posi.y )
call SetUnitZ( .spark, .posi.z )
//touch ground?
if GetUnitZ( .spark ) <= 1.00 or GetUnitFlyHeight( .spark ) <= 1.00 or .posi.z <= 1.00 then
call .destroy() //damage in destroy
endif
endmethod
private method calcRandomSpeed 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 = SPARK_SPEED
local vector temp = vector.create( r*Cos(a)*Cos(b), r*Cos(a)*Sin(b), r*Sin(a) )
set .startspeed = vector.create( temp.x * TIMER_INTERVAL, temp.y * TIMER_INTERVAL, temp.z * TIMER_INTERVAL )
endmethod
static method create takes Bolt b returns thistype
local thistype this = thistype.allocate()
set .caster = b.caster
call .calcRandomSpeed() //stes startspeed
set .boltspeed = vector.create( b.move.x, b.move.y, b.zdif )
set .posi = vector.create( b.posi.x, b.posi.y, b.posi.z )
set .level = b.level
set .spark = CreateUnit( GetOwningPlayer( b.bolt ), DUMMY_ID, .posi.x, .posi.y, 0.00 )
set .model = AddSpecialEffectTarget( SPARK_MODEL, .spark, "origin" )
set .t = NewTimer()
call SetUnitVertexColor( .spark, SPARK_RED, SPARK_GREEN, SPARK_BLUE, SPARK_ALPHA )
call SetUnitScale( .spark, SPARK_SIZE, SPARK_SIZE, SPARK_SIZE )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function SparkControl )
return this
endmethod
endstruct
private struct Bolt
unit bolt = null
unit caster = null
unit target = null
integer level = 1
real cd = 0.00
real zdif = 0.00
vector posi
vector move
vector start
vector ptarget
boolean utarget = true
timer t = null
effect model = null
method onDestroy takes nothing returns nothing
local unit u
call DestroyEffect( AddSpecialEffect( BOLT_HIT_SFX, .posi.x, .posi.y ) )
if .utarget then
call UnitDamageTarget( .caster, .target, BOLT_DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
else
call GroupEnumUnitsInRange( GROUP, .posi.x, .posi.y, BOLT_AOE( .level ), function IsAliveAndUnitAndNotMagicImmune )
loop
set u = FirstOfGroup( GROUP )
exitwhen u == null
if IsUnitEnemy( u, GetOwningPlayer( .bolt ) ) then
call UnitDamageTarget( .caster, u, BOLT_AOE_DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
endif
call GroupRemoveUnit( GROUP, u )
set u = null
endloop
endif
call .posi.destroy()
call .move.destroy()
call .start.destroy()
if .utarget == false then
call .ptarget.destroy()
endif
call ReleaseTimer( .t )
set .t = null
call DestroyEffect( .model )
set .model = null
call KillUnit( .bolt )
set .bolt = null
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(.bolt, i )
endmethod
method control takes nothing returns nothing
local real angle
local real xdif
local real ydif
local real dist
local integer i = 0
if GetWidgetLife( .bolt ) <= 0.405 then
call .destroy()
return
endif
if .utarget then
if IsUnitInRange( .bolt, .target, BOLT_COL_RANGE ) then
call .destroy()
return
endif
else
if DistanceBetweenCoordinates( .posi.x, .ptarget.x, .posi.y, .ptarget.y ) <= BOLT_COL_RANGE then
call .destroy()
return
endif
endif
//Bolt move
if .utarget then
set angle = AngleBetweenUnits( .bolt, .target ) * bj_DEGTORAD
else
set angle = AngleBetweenCoordinates( .posi.x, .ptarget.x, .posi.y, .ptarget.y ) * bj_DEGTORAD
endif
set xdif = .posi.x
set ydif = .posi.y
set .move.x = Cos( angle ) * BOLT_SPEED * TIMER_INTERVAL
set .move.y = Sin( angle ) * BOLT_SPEED * TIMER_INTERVAL
call .posi.add( .move )
set xdif = .posi.x - xdif
set ydif = .posi.y - ydif
call SetUnitX( .bolt, .posi.x )
call SetUnitY( .bolt, .posi.y )
call SetUnitFacing( .bolt, angle * bj_RADTODEG )
if .utarget then
set dist = DistanceBetweenCoordinates( .start.x, GetUnitX( .target), .start.y, GetUnitY( .target ) )
set .posi.z = ParabolaZ2( .start.z, GetUnitZ( .target ), dist * BOLT_HEIGHT, dist, DistanceBetweenCoordinates( .start.x, .posi.x, .start.y, .posi.y ) )
else
set dist = DistanceBetweenCoordinates( .start.x, .ptarget.x, .start.y, .ptarget.y )
set .posi.z = ParabolaZ2( .start.z, .ptarget.z, dist * BOLT_HEIGHT, dist, DistanceBetweenCoordinates( .start.x, .posi.x, .start.y, .posi.y ) )
endif
set .zdif = GetUnitZ( .bolt )
call SetUnitZ( .bolt, .posi.z )
set .zdif = GetUnitZ( .bolt ) - .zdif
call .Zangle( Atan(( .zdif / (SquareRoot(xdif*xdif + ydif*ydif))) ) )
//spark
set .cd = .cd - TIMER_INTERVAL
if .cd <= 0.00 then
set .cd = SPARK_CD
loop
exitwhen i >= SPARK_COUNT_PER_CD
call Spark.create( this )
set i = i + 1
endloop
endif
endmethod
static method create takes unit caster, unit target, real x, real y returns thistype
local thistype this = thistype.allocate()
local real angle
if target == null then
set .utarget = false
set .ptarget = vector.create( x, y, GetFloorHeight( x, y ) )
else
set .utarget = true
endif
set .caster = caster
set .target = target
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .cd = SPARK_CD
set .posi = vector.create( GetUnitX( caster ), GetUnitY( caster ), GetUnitZ( caster ))
if .utarget then
set angle = AngleBetweenUnits( caster, target )
else
set angle = AngleBetweenCoordinates( .posi.x, .ptarget.x, .posi.y, .ptarget.y )
endif
set .bolt = CreateUnit( GetOwningPlayer( caster ), DUMMY_ID, .posi.x, .posi.y, angle )
set .model = AddSpecialEffectTarget( BOLT_MODEL, .bolt, "origin" )
call SetUnitVertexColor( .bolt, BOLT_RED, BOLT_GREEN, BOLT_BLUE, BOLT_ALPHA )
call SetUnitScale( .bolt, BOLT_SIZE, BOLT_SIZE, BOLT_SIZE )
set .move = vector.create( ( BOLT_SPEED * TIMER_INTERVAL ) * Cos( angle * bj_DEGTORAD ), ( BOLT_SPEED * TIMER_INTERVAL ) * Sin( angle * bj_DEGTORAD ), 0.00 )
set .start = vector.create( .posi.x, .posi.y, .posi.z )
set .t = NewTimer()
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function BoltControl )
return this
endmethod
endstruct
private function IsSpell takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call Bolt.create( GetTriggerUnit(), GetSpellTargetUnit(), GetSpellTargetX(), GetSpellTargetY() )
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 G = vector.create( 0.00, 0.00, GRAVITY * TIMER_INTERVAL )
set TEMPVEC = vector.create( 0.00, 0.00, 0.00 )
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