Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Table
//***************************************************************
//* Table object 3.0
//* ------------
//*
//* set t=Table.create() - instanceates a new table object
//* call t.destroy() - destroys it
//* t[1234567] - Get value for key 1234567
//* (zero if not assigned previously)
//* set t[12341]=32 - Assigning it.
//* call t.flush(12341) - Flushes the stored value, so it
//* doesn't use any more memory
//* t.exists(32) - Was key 32 assigned? Notice
//* that flush() unassigns values.
//* call t.reset() - Flushes the whole contents of the
//* Table.
//*
//* call t.destroy() - Does reset() and also recycles the id.
//*
//* If you use HandleTable instead of Table, it is the same
//* but it uses handles as keys, the same with StringTable.
//*
//* You can use Table on structs' onInit if the struct is
//* placed in a library that requires Table or outside a library.
//*
//* You can also do 2D array syntax if you want to touch
//* mission keys directly, however, since this is shared space
//* you may want to prefix your mission keys accordingly:
//*
//* set Table["thisstring"][ 7 ] = 2
//* set Table["thisstring"][ 5 ] = Table["thisstring"][7]
//*
//***************************************************************
//=============================================================
globals
private constant integer MAX_INSTANCES=8100 //400000
//Feel free to change max instances if necessary, it will only affect allocation
//speed which shouldn't matter that much.
//=========================================================
private hashtable ht
endglobals
private struct GTable[MAX_INSTANCES]
method reset takes nothing returns nothing
call FlushChildHashtable(ht, integer(this) )
endmethod
private method onDestroy takes nothing returns nothing
call this.reset()
endmethod
//=============================================================
// initialize it all.
//
private static method onInit takes nothing returns nothing
set ht = InitHashtable()
endmethod
endstruct
//Hey: Don't instanciate other people's textmacros that you are not supposed to, thanks.
//! textmacro Table__make takes name, type, key
struct $name$ extends GTable
method operator [] takes $type$ key returns integer
return LoadInteger(ht, integer(this), $key$)
endmethod
method operator []= takes $type$ key, integer value returns nothing
call SaveInteger(ht, integer(this) ,$key$, value)
endmethod
method flush takes $type$ key returns nothing
call RemoveSavedInteger(ht, integer(this), $key$)
endmethod
method exists takes $type$ key returns boolean
return HaveSavedInteger( ht, integer(this) ,$key$)
endmethod
static method flush2D takes string firstkey returns nothing
call $name$(- StringHash(firstkey)).reset()
endmethod
static method operator [] takes string firstkey returns $name$
return $name$(- StringHash(firstkey) )
endmethod
endstruct
//! endtextmacro
//! runtextmacro Table__make("Table","integer","key" )
//! runtextmacro Table__make("StringTable","string", "StringHash(key)" )
//! runtextmacro Table__make("HandleTable","handle","GetHandleId(key)" )
endlibrary
//TESH.scrollpos=450
//TESH.alwaysfold=0
library MathFunctions
//********************************************************
//* :::::::::::::::::::::::::::::::::::::::::::::::::::: *
//* ::::::::::::::::::::MathLibrary::::::::::::::::::::: *
//* :::::::::::::::::::::::::::::::::::::::::::::::::::: *
//* : Compilation of the most important Math Functions : *
//* :::::::::::::::::::::::::::::::::::::::::::::::::::: *
//********************************************************
globals
private constant integer Iterations = 20 //* Logarithm Iterations!!
constant real PI = 3.1415926 //* the number PI
constant real TwoPI = 6.2831853 //* 2 * PI
constant real e = 2.7182818 //* Euler's number
constant real radian = .01745329 //* Conversion: Degree to Radian (PI/180)
constant real degree = 57.295779 //* Conversion: Radian to Degree (180/PI)
private location loc = Location(0.0,0.0)
private constant real AutoDestroyPeriod = 0.1
private constant boolean AutoDestroyVector = true
private constant timer AutoDestroyTimer = CreateTimer()
endglobals
// - # - This function allows you to get the n-th root of a value.
// - # - Requires 2 arguments:
// - # - - real x: the value that shall be rooted.
// - # - - real exp: the root amount.
function xRoot takes real x, real exp returns real
return Pow(x,1/exp)
endfunction
// - # - With this function you can return a correct angle value between 0 and 360.
// - # - Requires 1 argument:
// - # - - real angle: the angle that shall be converted
function realAngle takes real angle returns real
local real r=angle
loop
exitwhen r>=0 and r<=360
if r<0 then
set r=r+360
elseif r>360 then
set r=r-360
endif
endloop
return r
endfunction
// - # - With this function you can get the Angle between 2 Points.
// - # - Requires 4 arguments:
// - # - - real x0: the x-coordinate of the first Point.
// - # - - real y0: the y-coordinate of the first Point.
// - # - - real x1: the x-coordinate of the second Point.
// - # - - real y1: the y-coordinate of the second Point.
// - # - Angle will be returned in Radians
function Angle takes real x0, real y0, real x1, real y1 returns real
return Atan2((y1-y0),(x1-x0))
endfunction
// - # - With this function you can get the Distance between 2 Points.
// - # - Requires 4 arguments:
// - # - - real x0: the x-coordinate of the first Point.
// - # - - real y0: the y-coordinate of the first Point.
// - # - - real x1: the x-coordinate of the second Point.
// - # - - real y1: the y-coordinate of the second Point.
function Distance takes real x0, real y0, real x1, real y1 returns real
return SquareRoot((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0))
endfunction
// - # - With this function you can get the height-angle difference between 2 Points.
// - # - Requires 6 arguments:
// - # - - real x0: the x-coordinate of the first Point.
// - # - - real y0: the y-coordinate of the first Point.
// - # - - real z0: the z-coordinate of the first Point.
// - # - - real x1: the x-coordinate of the second Point.
// - # - - real y1: the y-coordinate of the second Point.
// - # - - real z1: the z-coordinate of the second Point.
function getZAngle takes real x0, real y0, real z0, real x1, real y1, real z1 returns real
return Atan2(z1-z0,SquareRoot((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)))
endfunction
// - # - With this function you can get the Distance between 2 Points in consideration of their heights.
// - # - Requires 6 arguments:
// - # - - real x0: the x-coordinate of the first Point.
// - # - - real y0: the y-coordinate of the first Point.
// - # - - real z0: the z-coordinate of the first Point.
// - # - - real x1: the x-coordinate of the second Point.
// - # - - real y1: the y-coordinate of the second Point.
// - # - - real z1: the z-coordinate of the second Point.
function Distance3D takes real x0, real y0, real z0, real x1, real y1, real z1 returns real
return SquareRoot((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)+(z1-z0)*(z1-z0))
endfunction
// - # - With this function you can get the natural Logarithm of a value.
// - # - Requires 1 argument:
// - # - - real x: the value you want to get the ln from.
function ln takes real x returns real
local integer i=Iterations
local real min=-88.
local real max=88.
local real mid=.0
loop
exitwhen (i<=0)
set mid=(max+min)/2
if Pow(bj_E,mid)>=x then
set max=mid
else
set min=mid
endif
set i=i-1
endloop
return mid
endfunction
// - # - With this function you can get the Logarithm to the base 10 of a value.
// - # - Requires 1 argument:
// - # - - real x: the value you want to get the Logarithm from.
function log takes real x returns real
local integer i=Iterations
local real min=-88.
local real max=88.
local real mid=.0
loop
exitwhen (i<=0)
set mid=(max+min)/2
if Pow(10,mid)>=x then
set max=mid
else
set min=mid
endif
set i=i-1
endloop
return mid
endfunction
// - # - With this function you can get the Logarithm to any base of a value.
// - # - Requires 2 arguments:
// - # - - real x: the value you want to get the Logarithm from.
// - # - - real base: the basis you want the Logarithm have to.
function logEx takes real x, real base returns real
local integer i=Iterations
local real min=-88.
local real max=88.
local real mid=.0
loop
exitwhen (i<=0)
set mid=(max+min)/2
if Pow(base,mid)>=x then
set max=mid
else
set min=mid
endif
set i=i-1
endloop
return mid
endfunction
// - # - With this function you can get the sign of a value. (positive or negative)
// - # - Requires 1 argument:
// - # - - real a: the value you want to get the sign from.
function getSign takes real a returns real
if a>=0 then
return 1.
else
return -1.
endif
endfunction
// - # - With this function you can get the Absolute value of a real.
// - # - Requires 1 argument:
// - # - - real a: the value you want the absolute from.
function absoluteReal takes real a returns real
if a>=0 then
return a
else
return -a
endif
endfunction
// - # - With this function you can get the Absolute value of an integer.
// - # - Requires 1 argument:
// - # - - integer i: the value you want the absolute from.
function absoluteInt takes integer i returns integer
if i>=0 then
return i
else
return -i
endif
endfunction
// - # - With this function you can get the Rest of a division.
// - # - Requires 2 arguments:
// - # - - integer dividend: the value that gets divided.
// - # - - integer divisor: the value that divides.
function modulo takes integer dividend, integer divisor returns integer
return absoluteInt(dividend-(dividend/divisor)*divisor)
endfunction
// - # - With this function you can get a common Parabola curve based on the Maximum height and Maximum distance.
// - # - Requires 3 arguments:
// - # - - real h: the maximum reachable height.
// - # - - real d: the maximum reachable distance.
// - # - - real x: the current reached distance.
function ParabolaZ takes real h, real d, real x returns real
return (4*h/d)*(d-x)*(x/d)
endfunction
// - # - With this function you can get an extended Parabola curve based on the
// - # - Maximum height and Maximum distance in consideration of the Height differences.
// - # - Requires 5 arguments:
// - # - - real h: the maximum reachable height.
// - # - - real d: the maximum reachable distance.
// - # - - real x: the current reached distance.
// - # - - real z0: the height of the starting point.
// - # - - real z1: the height of the finishing point.
function ParabolaZEx takes real h, real d, real x, real z0, real z1 returns real
return (4*h/d)*(d-x)*(x/d) + (((z1-z0)/d)*x+z0)
endfunction
// - # - With this struct you are able to create 3-Dimensional Coordinates.
// - # - To create a vector just call this:
// - # - x-Coordinate | y-Coordinate | z-Coordinate
// - # - local vector v=vector.create( x , y , z )
struct vector[20000]
//* x-coordinate of the vector
real x = 0.0
//* y-coordinate of the vector
real y = 0.0
//* z-coordinate of the vector
real z = 0.0
//* shall this vector be autodestroyed
private boolean autoDestroy=AutoDestroyVector
private real autoTime =0.0
private boolean inUse =false
private static integer vectorCount = 1
method onDestroy takes nothing returns nothing
set .inUse=false
set .autoTime=0.0
set .autoDestroy=AutoDestroyVector
endmethod
// - # - With this function you can create a vector.
// - # - Requires 3 arguments:
// - # - - real x: the x-coordinate
// - # - - real y: the y-coordinate
// - # - - real z: the z-coordinate
static method create takes real x, real y, real z returns thistype
local thistype vec=thistype.allocate()
set vec.x=x
set vec.y=y
set vec.z=z
set vec.inUse=true
if vec==thistype.vectorCount then
set thistype.vectorCount=thistype.vectorCount+1
endif
return vec
endmethod
// - # - With this function you can stop the autorecycling of a vector.
method stopAutoClear takes nothing returns nothing
set this.autoDestroy=false
endmethod
// - # - With this function you can return the length of a vector.
method operator length takes nothing returns real
return SquareRoot(this.x*this.x+this.y*this.y+this.z*this.z)
endmethod
// - # - With this function you can return the Angle between the
// - # - x-coordinate and y-coordinate.
method operator xyAngle takes nothing returns real
return Angle(0.,0.,this.x,this.y)
endmethod
// - # - With this function you can return the Angle between the
// - # - Ground and the vectors z-coordinate.
method operator zAngle takes nothing returns real
return getZAngle(0.,0.,0.,this.x,this.y,this.z)
endmethod
// - # - With this function you can add a vector to another.
// - # - Requires 1 argument:
// - # - - vector additive: the vector that shall be added.
method add takes thistype additive returns nothing
set this.x=this.x+additive.x
set this.y=this.y+additive.y
set this.z=this.z+additive.z
endmethod
// - # - With this function you can sum 2 vectors to a new one.
// - # - Requires 2 arguments:
// - # - - vector start: the starting vector.
// - # - - vector end: the vector that gets added to the starting vector.
static method sum takes thistype start, thistype end returns thistype
return thistype.create(start.x+end.x,start.y+end.y,start.z+end.z)
endmethod
// - # - With this function you can subtract a vector from another.
// - # - Requires 1 argument:
// - # - - vector subtrahend: the vector that shall be subtracted.
method subtract takes thistype 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
// - # - With this function you can subtract 2 vectors to a new one.
// - # - Requires 2 arguments:
// - # - - vector start: the starting vector.
// - # - - vector end: the vector that gets subtracted from the starting vector.
static method difference takes thistype start, thistype end returns thistype
return thistype.create(end.x-start.x,end.y-start.y,end.z-start.z)
endmethod
// - # - With this function you can scale a vector.
// - # - Requires 1 argument:
// - # - - real factor: the scaling factor.
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
// - # - With this function you can scale a vector to a new one.
// - # - Requires 2 arguments:
// - # - - vector a: the vector that shall be scaled.
// - # - - real factor: the scaling factor.
static method scaleVector takes thistype a, real factor returns thistype
return thistype.create(a.x*factor,a.y*factor,a.z*factor)
endmethod
// - # - With this function you can set a vectors length.
// - # - Requires 1 argument:
// - # - - real length: the new length the vector shall have.
method setLength takes real length returns nothing
local real l=SquareRoot(this.x*this.x+this.y*this.y+this.z*this.z)
if l!=0 then
call this.scale(length/l)
endif
endmethod
// - # - With this function you can get the length of a vector.
// - # - Requires 1 argument:
// - # - - vector a: the vector you want the length from.
static method getLength takes thistype a returns real
return SquareRoot(a.x*a.x+a.y*a.y+a.z*a.z)
endmethod
// - # - With this function you can get the ScalarProduct of 2 vectors.
// - # - Requires 2 arguments:
// - # - - vector a: one of the 2 vectors.
// - # - - vector b: one of the 2 vectors.
static method scalarProduct takes thistype a, thistype b returns real
return (a.x*b.x+a.y*b.y+a.z*b.z)
endmethod
// - # - With this function you can get the VectorProduct of 2 vectors in a new vector.
// - # - Requires 2 arguments:
// - # - - vector a: one of the 2 vectors.
// - # - - vector b: one of the 2 vectors.
static method vectorProduct takes thistype a, thistype b returns thistype
return thistype.create(a.y*b.z-a.z-b.y,a.z*b.x-a.x-b.z,a.x*b.y-a.y*b.x)
endmethod
// - # - With this function you can create the UnitVector of a vector.
// - # - Requires 1 argument:
// - # - - vector a: the vector you want the UnitVector from.
static method unitVector takes thistype a returns thistype
return thistype.scaleVector(a,1/a.length)
endmethod
// - # - With this function you can get the Angle between a vector and another.
// - # - Requires 1 argument:
// - # - - vector a: the vector you want the angle from.
method angle takes thistype a returns real
return Atan(scalarProduct(this,a)/(a.length*this.length))
endmethod
// - # - With this function you can get the Angle between 2 vectors.
// - # - Requires 2 arguments:
// - # - - vector a: one of the 2 vectors you want the Angle between.
// - # - - vector b: one of the 2 vectors you want the Angle between.
static method getAngle takes thistype a, thistype b returns real
return Acos(scalarProduct(a,b)/(a.length*b.length))
endmethod
// - # - With this function you can mirror a vector.
// - # - Requires 1 argument:
// - # - - vector projector: the vector you want the other vector to be mirrored at.
method mirrorVector takes thistype projector returns nothing
if projector.length!=0 then
set this.x=2*projector.x-this.x
set this.y=2*projector.y-this.y
set this.z=2*projector.z-this.z
endif
endmethod
// - # - With this function you can mirror a vector on another to a new vector.
// - # - Requires 2 arguments:
// - # - - vector projector: the vector you want the other vector to be mirrored at.
// - # - - vector projected: the vector you want to be mirrored.
static method mirrorVectorEx takes thistype projector, thistype projected returns thistype
if projector.length!=0 then
return thistype.create(2*projector.x-projected.x,2*projector.y-projected.y,2*projector.z-projected.z)
else
return thistype.create(0.,0.,0.)
endif
endmethod
// - # - With this function you can project a vector.
// - # - Requires 1 argument:
// - # - - vector direction: the vector you want the other projected to.
method projectVector takes thistype direction returns nothing
local real factor=0.0
if direction.length!=0 then
set factor=this.length/direction.length
set this.x=direction.x*factor
set this.y=direction.y*factor
set this.z=direction.z*factor
endif
endmethod
// - # - With this function you can project a vector to another one to a new vector.
// - # - Requires 2 arguments:
// - # - - vector projected: the vector that gets projected.
// - # - - vector direction: the vector you want the other projected to.
static method projectVectorEx takes thistype projected, thistype direction returns thistype
local real factor=0.0
if direction.length!=0 then
set factor=projected.length/direction.length
return thistype.create(direction.x*factor,direction.y*factor,direction.z*factor)
else
return thistype.create(0.,0.,0.)
endif
endmethod
// - # - With this function you can rotate a vector
// - # - requires 2 values:
// - # - - xyAngle: the horizontal rotation angle
// - # - - zAngle: the vertical rotation angle
method rotate takes real xyAngle, real zAngle returns nothing
local real a=this.length
local real b=this.xyAngle
set this.x=a*Cos(b+xyAngle)
set this.y=a*Sin(b+xyAngle)
set b=this.zAngle
set this.x=x*Cos(b+zAngle)
set this.y=y*Cos(b+zAngle)
set this.z=z*Sin(b+zAngle)
endmethod
// - # - With this function you can rotate any vector to a new one.
// - # - Requires 3 arguments:
// - # - - vector a: the vector that shall be rotated.
// - # - - real xyAngle: the horizontal rotation angle.
// - # - - real zAngle: the vertical rotation angl.
static method rotateVector takes thistype a, real xyAngle, real zAngle returns thistype
local real d=a.length
local real e=a.xyAngle
local real f=a.zAngle
local real x=d*Cos(e+xyAngle)
local real y=d*Sin(e+xyAngle)
local real z=d*Sin(f+zAngle)
set x=d*Cos(f+zAngle)
set y=d*Cos(f+zAngle)
return thistype.create(x,y,z)
endmethod
// - # - With this function you can check whether a vector is in sphere of a location with a specific radius.
// - # - Requires 4 arguments:
// - # - - real x: the x-coordinate of the sphere.
// - # - - real y: the y-coordinate of the sphere.
// - # - - real z: the z-coordinate of the sphere.
// - # - - real radius: the radius of the sphere.
method isInSphere takes real x, real y, real z, real radius returns boolean
if .x>x-radius and .x<x+radius and .y>y-radius and .y<y+radius and .z>z-radius and .z<z+radius then
return true
else
return false
endif
endmethod
// - # - With this function you can check whether a vector is in sphere of another vector.
// - # - Requires 3 arguments:
// - # - - vector a: one of the 2 vectors.
// - # - - vector b: one of the 2 vectors.
// - # - - real radius: the radius of the sphere.
static method vectorInSphere takes vector a, vector b, real radius returns boolean
return a.isInSphere(b.x,b.y,b.z,radius)
endmethod
static method autoClear takes nothing returns nothing
local integer i=0
loop
exitwhen i==thistype.vectorCount
if thistype(i).autoDestroy and thistype(i).inUse then
if thistype(i).autoTime>=AutoDestroyPeriod then
set thistype(i).inUse=false
call thistype(i).destroy()
endif
set thistype(i).autoTime=thistype(i).autoTime+0.05
endif
set i=i+1
endloop
endmethod
private static method onInit takes nothing returns nothing
call TimerStart(AutoDestroyTimer,0.05,true,function thistype.autoClear)
endmethod
endstruct
function LocationZ takes real x, real y returns real
call MoveLocation(loc,x,y)
return GetLocationZ(loc)
endfunction
endlibrary
//TESH.scrollpos=9
//TESH.alwaysfold=0
library Dummy requires MathFunctions
// - # - Requirements - # - //
// - # - MathFunctions - # - //
// - # - - - - - - - - - # - //
globals
private constant integer DummyID = 'face' //* The RawCode for your DummyUnit
private constant integer HeightEnabler = 'Amrf' //* The RawCode for the FlyHack Ability
private constant real RecyclePeriod = 0.2 //* The Period for the recycling process
private constant real RecycleUnused = 15. //* The Time after which unused Dummys get recycled
private constant real ZFacingFactor = 0.7 //* Factor to convert Z-Angle to Z-Facing-Angle
private constant boolean AutoRecycle = true //* The Default whether a dummy shall get auto-recycled or not
endglobals
// - # - The Dummy struct for all your needs.
// - # - To create a dummy unit use this function:
// - # - x-Coordinate | y-Coordinate | FacingAngle
// - # - local Dummy d=Dummy.create( x , y , facing )
struct Dummy
unit dummy //* The dummy unit
private real recycle = .0 //* The Recycle counter. When this reaches the RecycleUnused value
//* the dummy instance will be recycled
private real recycleTime = RecycleUnused
private real xPos = .0 //* The x-coordinate of the dummy
private real yPos = .0 //* The y-coordinate of the dummy
private real zPos = .0 //* The z-coordinate of the dummy
private real faceAngle = .0 //* The dummy units facing angle
private real turnSpeed = 1.0 //* The dummy units turn speed
private real growSize = 1.0 //* The dummy units size
private integer red = 255 //* The dummy units vertex red color
private integer green = 255 //* The dummy units vertex green color
private integer blue = 255 //* The dummy units vertex blue color
private integer alpha = 0 //* The dummy units vertex alpha value
private boolean autoRecycle = AutoRecycle
private boolean inUse = false
private static integer dummyCount = 1
private static timer recycler = CreateTimer()
// - # - With this function you can clear a dummy Instance.
method clear takes nothing returns nothing
set this.recycle=.0
set this.inUse=false
set this.autoRecycle=AutoRecycle
call ShowUnit(this.dummy,false)
call RemoveUnit(this.dummy)
call this.destroy()
endmethod
// - # - With this function you can turn of the Autorecycling process for the Dummy.
method turnOffRecycling takes nothing returns nothing
set this.autoRecycle=false
endmethod
private method resetRecycler takes nothing returns nothing
set this.recycle=.0
endmethod
private static method Recycle takes nothing returns nothing
local integer index=1
loop
exitwhen index==thistype.dummyCount
if thistype(index).autoRecycle and thistype(index).inUse then
set thistype(index).recycle=thistype(index).recycle+RecyclePeriod
if thistype(index).recycle>=thistype(index).recycleTime then
call thistype(index).clear()
endif
endif
set index=index+1
endloop
endmethod
// - # - With this function you can create a dummy.
// - # - Requires 3 arguments:
// - # - - real x: the x-coordinate where the dummy unit shall be created.
// - # - - real y: the y-coordinate where the dummy unit shall be created.
// - # - - real facing: the default facing the dummy unit shall have.
static method create takes real x, real y, real facing returns thistype
local thistype temp=thistype.allocate()
set temp.dummy=CreateUnit(Player(15),DummyID,x,y,facing)
set temp.turn=GetUnitTurnSpeed(temp.dummy)
set temp.x=x
set temp.y=y
set temp.faceAngle=facing
set temp.zfacing=0
set temp.inUse=true
call UnitAddAbility(temp.dummy,HeightEnabler)
call UnitRemoveAbility(temp.dummy,HeightEnabler)
if temp==thistype.dummyCount then
set thistype.dummyCount=thistype.dummyCount+1
endif
return temp
endmethod
private static method onInit takes nothing returns nothing
call TimerStart(thistype.recycler,RecyclePeriod,true,function Dummy.Recycle)
endmethod
// - # - With this function you can set the time after which the dummy is recycled.
// - # - Requires 1 argument:
// - # - - real time: the time after which the dummy gets recycled.
method operator recycleAfter= takes real time returns nothing
set this.recycleTime=time
endmethod
// - # - With this function you can change the Dummys owner.
// - # - Requires 1 argument:
// - # - - player whichPlayer: the new Owner.
method operator owner= takes player whichPlayer returns nothing
call SetUnitOwner(this.dummy,whichPlayer,true)
call this.resetRecycler()
endmethod
// - # - With this function you can get the Dummys current x-coordinate.
method operator x takes nothing returns real
call this.resetRecycler()
return this.xPos
endmethod
// - # - With this function you can move the Dummy to a new x-coordinate.
// - # - Requires 1 argument:
// - # - - real x: the new x-coordinate.
method operator x= takes real x returns nothing
set this.xPos=x
call SetUnitX(this.dummy,x)
call this.resetRecycler()
endmethod
// - # - With this function you can get the Dummys current y-coordinate.
method operator y takes nothing returns real
call this.resetRecycler()
return this.yPos
endmethod
// - # - With this function you can move the Dummy to a new y-coordinate.
// - # - Requires 1 argument:
// - # - - real y: the new y-coordinate.
method operator y= takes real y returns nothing
set this.yPos=y
call SetUnitY(this.dummy,y)
call this.resetRecycler()
endmethod
// - # - With this function you can get the Dummys current z-coordinate.
method operator z takes nothing returns real
call this.resetRecycler()
return this.zPos
endmethod
// - # - With this function you can move the Dummy to a new z-coordinate.
// - # - Requires 1 argument:
// - # - - real z: the new z-coordinate.
method operator z= takes real z returns nothing
set this.zPos=z
call SetUnitFlyHeight(this.dummy,z,.0)
call this.resetRecycler()
endmethod
// - # - With this function you can get the Dummys current Facingangle.
method operator facing takes nothing returns real
call this.resetRecycler()
return this.faceAngle
endmethod
// - # - With this function you can set the Dummys Facingangle.
// - # - Requires 1 argument:
// - # - - real facing: the new Facingangle.
method operator facing= takes real facing returns nothing
set this.faceAngle=realAngle(facing)
call SetUnitFacing(this.dummy,facing)
call this.resetRecycler()
endmethod
// - # - With this function you can set the Dummys Z-Facing.
//* requires 1 argument + a special imported model:
// - # - - real facing: the z angle the dummy shall be facing.
method operator zfacing= takes real facing returns nothing
local integer z=R2I(facing*ZFacingFactor)
loop
exitwhen z>=0 and z<=252
if z>252 then
set z=z-252
else
set z=z+252
endif
endloop
call SetUnitAnimationByIndex(this.dummy,z)
call this.resetRecycler()
endmethod
// - # - With this function you can set the Dummys vertex coloring.
// - # - Requires 4 arguments:
// - # - - integer red: the vertex coloring red.
// - # - - integer green: the vertex coloring green.
// - # - - integer blue: the vertex coloring blue.
// - # - - integer alpha: the vertex value alpha.
method color takes integer red, integer green, integer blue, integer alpha returns nothing
set this.red=red
set this.green=green
set this.blue=blue
set this.alpha=alpha
call SetUnitVertexColor(this.dummy,red,green,blue,alpha)
call this.resetRecycler()
endmethod
// - # - With this function you can get the Dummys Turnspeed
method operator turn takes nothing returns real
call this.resetRecycler()
return this.turnSpeed
endmethod
// - # - With this function you can set the Dummys Turnspeed.
// - # - Requires 1 argument:
// - # - - real turn: the new Turnspeed.
method operator turn= takes real turn returns nothing
set this.turnSpeed=turn
call SetUnitTurnSpeed(this.dummy,turn)
call this.resetRecycler()
endmethod
// - # - With this function you can get the Dummys size scaling ( only if you scaled it befor )
method operator size takes nothing returns real
call this.resetRecycler()
return this.growSize
endmethod
// - # - With this function you can set the Dummys size scaling.
// - # - Requires 1 argument:
// - # - - real size: the new scaling Size.
method operator size= takes real size returns nothing
set this.growSize=size
call SetUnitScale(this.dummy,size,size,size)
call this.resetRecycler()
endmethod
// - # - With this function you can add an Effect to the Dummy.
// - # - Requires 2 arguments:
// - # - - string mdlpath: the path for the Effect.
// - # - - string attach: the attachpoint where the Effect shall be attached.
method addEffect takes string mdlpath, string attach returns nothing
call AddSpecialEffectTarget(mdlpath,this.dummy,attach)
call this.resetRecycler()
endmethod
// - # - With this function you can add an ability to the Dummy.
// - # - Requires 1 argument:
// - # - - integer abilID: the AbilityId of the Ability that shall be added.
method addAbility takes integer abilID returns nothing
call UnitAddAbility(this.dummy,abilID)
call this.resetRecycler()
endmethod
// - # - With this function you can set the level of an Ability for the Dummy.
// - # - Requires 2 arguments:
// - # - - integer abilID: the AbilityId of the Ability.
// - # - - integer level: the new level.
method setAbilityLevel takes integer abilID, integer level returns nothing
call SetUnitAbilityLevel(this.dummy,abilID,level)
call this.resetRecycler()
endmethod
// - # - With this function you can remove an Ability of the Dummy.
// - # - Requires 1 argument:
// - # - - integer abilID: the AbilityId of the Ability that shall be removed.
method removeAbility takes integer abilID returns nothing
call UnitRemoveAbility(this.dummy,abilID)
call this.resetRecycler()
endmethod
// - # - With this function you can order the Dummy a target order.
// - # - Requires 2 arguments:
// - # - - integer orderID: The OrderId of the order.
// - # - - widget target: That target of the order.
method castTargetAbility takes integer orderID, widget target returns nothing
call IssueTargetOrderById(this.dummy,orderID,target)
call this.resetRecycler()
endmethod
// - # - With this function you can order the Dummy an instant order.
// - # - Requires 1 argument:
// - # - - integer orderID: The OrderId of the order.
method castInstantAbility takes integer orderID returns nothing
call IssueImmediateOrderById(this.dummy,orderID)
call this.resetRecycler()
endmethod
// - # - With this function you can order the Dummy a point order.
// - # - Requires 3 arguments:
// - # - - integer orderID: The OrderId of the order.
// - # - - real x: the x-coordinate of the target Point.
// - # - - real y: the y-coordinate of the target Point.
method castPointAbility takes integer orderID, real x, real y returns nothing
call IssuePointOrderById(this.dummy,orderID,x,y)
call this.resetRecycler()
endmethod
endstruct
endlibrary
//TESH.scrollpos=160
//TESH.alwaysfold=0
library MissileSystem requires Dummy, MathFunctions
// - # - Requirements - # - //
// - # - Dummy - # - //
// - # - MathFunctions - # - //
// - # - - - - - - - - - # - //
globals
//* This Height applies when an Unit has a Flyheight of 0.
private constant real Missile_DefaultHeight = 50.
//* This is the Timer Interval
private constant real Missile_TimerPeriod = 0.03
//* This is the Maximum Width a projectile can reach in XY-Direction while flying
private constant real Missile_MaxXYArcWidth = 200.
//* This is the Maximum Height a projectile can reach during a Parabola Flight.
//* This is not the Maximum Height the projectile will reach.
private constant real Missile_MaxZArcHeight = 300.
//* The Range in which other projectiles, units, destructables etc. are detected
private constant real Missile_DetectionRange = 32.
//* The Factor to convert normal Wc3 speed to projectile speed
private constant real Missile_SpeedConverter = 0.0233333
//* The Default whether a projectile can hit units on its way
private constant boolean Missile_DefaultHitUnits = false
//* The Default whether a projectile can hit destructables on its way
private constant boolean Missile_DefaultHitDestructables = false
//* The Default whether a projectile can hit other missiles on its way
private constant boolean Missile_DefaultHitMissiles = false
//* The Default whether a projectile can hit walls on its way
private constant boolean Missile_DefaultHitWalls = false
//* The Default whether a projectile will be cleared and destroyed until it reaches its target
private constant boolean Missile_DefaultClearOnTargetReach = true
endglobals
interface eventHandler
//* This method will fire when the projectile reaches its Target Point or Target Unit
method onTargetReach takes nothing returns nothing defaults nothing
//* This method will fire when any other unit is hit on its way. (requires UnitCollision enabled)
method onUnitHit takes unit whichUnit returns nothing defaults nothing
//* This method will fire when a destructable is hit on its way. (requires DestructableCollision enabled)
method onDestructableHit takes destructable whichDestructable returns nothing defaults nothing
//* This method will fire when a wall is hit on its way. (requires WallCollision enabled)
method onWallHit takes real x, real y returns nothing defaults nothing
//* This method will fire when any other missile is hit on its way.
method onMissileHit takes Missile missile returns nothing defaults nothing
//* This method will fire whenever the projectile starts to move.
method onStart takes nothing returns nothing defaults nothing
//* This method will fire whenever the projectile is created.
method onCreate takes nothing returns nothing defaults nothing
//* This method will fire every TimerInterval aslong as the projectile is on its way.
method onLoop takes nothing returns nothing defaults nothing
//* This method will fire whenever the projectile is destroyed.
method onDestruction takes nothing returns nothing defaults nothing
endinterface
struct Missile extends eventHandler
// - # - Missile Main Variables - # - //
//* The missiles body that moves.
Dummy dummy
//* The missiles model path
private string missilePath
//* The missiles starting position.
private vector start
//* The missiles current position. (Does not include any XY-Arc positions)
private vector position
//* The missiles targeting position.
private vector target
//* The missiles xyz-speed.
private vector speed
// - # - - - - - - - - - - - - - - # - //
// - # Missile Movement Variables - # - //
//* The missiles maximum reachable Height in any Parabola Movement.
private real zArc = 0.0
//* The missiles maximum reachable Width in any XY-Movement.
private real xyArc = 0.0
//* The missiles currently traveled Distance.
private real movedDistance = 0.0
//* The Distance the missile has to travel.
private real distanceToMove = 0.0
//* The speed increment of the missile.
private real speedFactor = 1.0
// - # - - - - - - - - - - - - - - - # - //
// - # - Targeting and Enumeration Stuff - # - //
//* The missiles current targeted Unit. (is not set when you declare a Point as the target!)
private unit missileTarget = null
//* The missiles enumeration group.
private group enumGroup = CreateGroup()
// - # - - - - - - - - - - - - - - - - - - # - //
// - # - Missile Behaviour Variables - # - //
//* Can the missile hit other missiles on its way.
private boolean hitMissiles = Missile_DefaultHitMissiles
//* Can the missile hit units on its way.
private boolean hitUnits = Missile_DefaultHitUnits
//* Can the missile hit destructables on its way.
private boolean hitDestructables = Missile_DefaultHitDestructables
//* Can the missile hit walls on its way.
private boolean hitWalls = Missile_DefaultHitWalls
//* Is the missile destroyed after it reached its target.
private boolean clearOnTargetReach = Missile_DefaultClearOnTargetReach
// - # - - - - - - - - - - - - - - - - - # - //
// - # - Important Missile Conditions - # - //
//* Is the missile currently alive.
private boolean alive = false
//* Is the missile moving.
private boolean inMotion = false
// - # - - - - - - - - - - - - - - - - # - //
// - # - Some Struct Variables - - - - # - //
//* A temporarily Instance of the Struct.
private static thistype currentInstance = 0
//* Shows the limit of the currently created Instances
private static integer missileCount = 1
//* The timer that loops the movement
private static timer missileTimer = CreateTimer()
//* The rect for destructable enumeration
private static rect locRect
//* A very important helper vector
private static vector helper
// - # - - - - - - - - - - - - - - - - # - //
// - # - The function to get a missile Instance if we know the missiles body unit
private static method operator [] takes unit whichUnit returns thistype
local integer i=1
loop
exitwhen i==thistype.missileCount
if thistype(i).dummy.dummy==whichUnit then
return thistype(i)
endif
set i=i+1
endloop
return 0
endmethod
// - # - The function to create a new missile Instance.
// - # - Requires 4 arguments:
// - # - - real x: the x-coordinate where the missile shall be created.
// - # - - real y: the y-coordinate where the missile shall be created.
// - # - - real z: the z-coordinate where the missile shall be created.
// - # - - string mdlPath: The model path the missile shall have.
static method create takes nothing returns thistype
local thistype missile=thistype.allocate()
// - # - Vector Setup - # - //
//* Creating the vector at the Starting Coordinations.
set missile.start=vector.create(0.,0.,0.)
//* Creating the vector at the current Dummy position.
set missile.position=vector.create(0.,0.,0.)
set missile.target=vector.create(0.,0.,0.)
set missile.speed=vector.create(0.,0.,0.)
//* Turning off the vectors autorecycling.
call missile.start.stopAutoClear()
call missile.position.stopAutoClear()
call missile.speed.stopAutoClear()
call missile.target.stopAutoClear()
// - # - - - - - - - - - # - //
set missile.alive=true
call missile.onCreate()
if missile==thistype.missileCount then
set thistype.missileCount=thistype.missileCount+1
endif
return missile
endmethod
private method createDummy takes nothing returns nothing
// - # - Dummy Setup - # - //
set .dummy=Dummy.create(.start.x,.start.y,.speed.xyAngle*degree) //* Creating a new Dummy instance.
set .dummy.turn=10. //* Increasing the Dummys turnrate to max.
set .dummy.z=.start.z-LocationZ(.start.x,.start.y)
call .dummy.addEffect(.missilePath,"origin")
call .dummy.turnOffRecycling() //* Turning off the Dummys autorecycling.
// - # - - - - - - - - # - //
endmethod
// - # - The function to clear and recycle a missile Instance.
method clear takes nothing returns nothing
call .onDestruction()
call .dummy.clear()
call .start.destroy()
call .target.destroy()
call .speed.destroy()
call .position.destroy()
call DestroyGroup(.enumGroup)
set .inMotion=false
call .destroy()
endmethod
// - # - With this function you can set the Missiles starting Coordinates
// - # - Requires 3 arguments:
// - # - - real x: The new x-coordinate
// - # - - real y: The new y-coordinate
// - # - - real z: The new z-coordinate
method setMissileStartPosition takes real x, real y, real z returns nothing
if not .inMotion then
set .start.x=x
set .start.y=y
set .start.z=z+LocationZ(x,y)
set .position.x=x
set .position.y=y
set .position.z=z+LocationZ(x,y)
endif
endmethod
// - # - Target Arival Operators - # - //
// - # - With this operator you can get the x-coordinate of the missile.
// - # - The missile must have arrived at the Target location.
method operator x takes nothing returns real
if not .alive then
return .position.x
endif
return 0.
endmethod
// - # - With this operator you can get the y-coordinate of the missile.
// - # - The missile must have arrived at the Target location.
method operator y takes nothing returns real
if not .alive then
return .position.y
endif
return 0.
endmethod
// - # - With this operator you can get the z-coordinate of the missile.
// - # - The missile must have arrived at the Target location.
method operator z takes nothing returns real
if not .alive then
return .position.z
endif
return 0.
endmethod
// - # - With this operator you can get the targeted Unit of the missile.
// - # - The missile must have arrived at the Target location.
method operator targetUnit takes nothing returns unit
if not .alive then
return this.missileTarget
endif
return null
endmethod
// - # - - - - - - - - - - - - - - - - - # - //
// - # - Missile Manipulation Functions # - //
// - # - With this function you can reduce the missiles speed by a specific amount.
// - # - You can use this even during the missiles flight.
// - # - Requires 1 argument:
// - # - - real speed: The speed decrement.
method reduceSpeed takes real speed returns nothing
local real r=(.speedFactor-speed*Missile_SpeedConverter)/.speedFactor
if r<=0 then
call .speed.destroy()
set .speed=vector.unitVector(vector.difference(.position,.target))
call .speed.stopAutoClear()
set .speedFactor=1.
else
call .speed.scale(r)
set .speedFactor=.speedFactor-speed*Missile_SpeedConverter
endif
endmethod
// - # - With this function you can change the missiles owner.
// - # - Requires 1 arguement:
// - # - - player owner: The missiles new owner.
method operator missileOwner= takes player owner returns nothing
set .dummy.owner=owner
endmethod
// - # - With this function you can change the missiles model
// - # - Requires 1 argument:
// - # - - string path: The missiles new models path
method operator modelPath= takes string path returns nothing
set .missilePath=path
endmethod
// - # - With this function you can change the missiles zArc. (Makes the missile fly a Parabola)
// - # - Requires 1 argument:
// - # - - real arc: The missiles new zArc.
// - # - ! Insert values like in normal Object Editor arc Movements (e.g. between 0 and 1) !
method operator setZArc= takes real arc returns nothing
set .zArc=arc*Missile_MaxZArcHeight
endmethod
// - # - With this function you can change the missiles xyArc. (Makes the missile fly curves)
// - # - Requires 1 argument:
// - # - - real arc: The missiles new xyArc.
// - # - ! Insert values like in normal Object Editor arc Movements (e.g. between 0 and 1) !
// - # - !! To get right curve use negative values, for left curves use positive values !!
method operator setXYArc= takes real arc returns nothing
set .xyArc=arc*Missile_MaxXYArcWidth
endmethod
// - # - With this function you can change the missiles speed.
// - # - Requires 1 argument:
// - # - - real speed: The missiles new speed.
// - # - ! Insert values like in normal Object Editor speed changes (e.g. a speed of 900) !
method operator setSpeed= takes real speed returns nothing
set .speedFactor=.speedFactor*speed*Missile_SpeedConverter
call .speed.scale(.speedFactor)
endmethod
// - # - With this function you can start the missiles movement.
method startMotion takes nothing returns nothing
// - # - Dummy Creation - # - //
call .createDummy()
// - # - - - - - - - - - # - //
call .onStart()
set .inMotion=true
endmethod
// - # - - - - - - - - - - - - - - - - - # - //
// - # Missile Behaviour Manipulation - # - //
// - # - With this function you can stop the missile to be destroyed after it reached the target location.
method disableOnTargetDestruction takes nothing returns nothing
set .clearOnTargetReach=false
endmethod
// - # - With this function you can enable the Collision with Walls.
method enableWallCollision takes nothing returns nothing
set .hitWalls=true
endmethod
// - # - With this function you can enable the Collision with Units.
method enableUnitCollision takes nothing returns nothing
set .hitUnits=true
endmethod
// - # - With this function you can enable the Collision with Destructables.
method enableDestructableCollision takes nothing returns nothing
set .hitDestructables=true
endmethod
// - # - With this function you can enable the Collision with other Missiles.
method enableMissileCollision takes nothing returns nothing
set .hitMissiles=true
endmethod
// - # - - - - - - - - - - - - - - - - # - //
// - # - Target Assignment Functions - # - //
// - # - With this function you can assign a new Target Position.
// - # - Requires 3 arguments:
// - # - - real x: the new x-coordinate.
// - # - - real y: the new y-coordinate.
// - # - - real z: the new z-coordinate.
// - # - ! This function can only be used when the current target location has been reached !
method assignNewTargetPoint takes real x, real y, real z returns nothing
if not .clearOnTargetReach and not .alive then
// - # - New Start Assignment - # - //
set .start.x=.dummy.x
set .start.y=.dummy.y
set .start.z=.dummy.z+LocationZ(.dummy.x,.dummy.y)
// - # - - - - - - - - - - - - - # - //
// - # - New Target Assignment - # - //
set .target.x=x
set .target.y=y
set .target.z=z+LocationZ(.target.x,.target.y)
// - # - - - - - - - - - - - - - # - //
// - # - New Distance Assignment - # - //
set .distanceToMove=vector.difference(.start,.target).length
set .movedDistance=0
// - # - - - - - - - - - - - - - - # - //
// - # - New Speed Assignment - # - //
call .speed.destroy()
set .speed=vector.unitVector(vector.difference(.start,.target))
call .speed.scale(.speedFactor)
call .speed.stopAutoClear()
// - # - - - - - - - - - - - - - # - //
set .alive=true
endif
endmethod
// - # - With this function you assign the first target location.
// - # - Requires 3 arguments:
// - # - - real x: the new x-coordinate.
// - # - - real y: the new y-coordinate.
// - # - - real z: the new z-coordinate.
// - # - ! Only works befor the missile starts moving for the first time !
method assignTargetPoint takes real x, real y, real z returns nothing
if not .inMotion then
// - # - Target Assignment - # - //
set .target.x=x
set .target.y=y
set .target.z=z+LocationZ(.target.x,.target.y)
// - # - - - - - - - - - - - # - //
// - # - Distance Assignment - # - //
set .distanceToMove=vector.difference(.start,.target).length
// - # - - - - - - - - - - - - # - //
// - # - Speed Assignment - # - //
call .speed.destroy()
set .speed=vector.unitVector(vector.difference(.start,.target))
call .speed.scale(.speedFactor)
call .speed.stopAutoClear()
// - # - - - - - - - - - - # - //
endif
endmethod
// - # - With this function you can assign a new Unit as the target.
// - # - Requires 1 argument:
// - # - - unit whichUnit: the new target Unit.
// - # - ! This function can only be used when the current Target Unit has been reached !
method assignNewTargetUnit takes unit whichUnit returns nothing
if not .clearOnTargetReach and not .alive then
// - # - New Unit Assignment - # - //
set .missileTarget=whichUnit
// - # - - - - - - - - - - - - # - //
// - # - New Start Assignment - # - //
set .start.x=.dummy.x
set .start.y=.dummy.y
set .start.z=.dummy.z+LocationZ(.dummy.x,.dummy.y)
// - # - - - - - - - - - - - - - # - //
// - # - New Target Assignment - # - //
set .target.x=x
set .target.y=y
if GetUnitFlyHeight(whichUnit)==0. then
set .target.z=Missile_DefaultHeight+LocationZ(.target.x,.target.y)
else
set .target.z=GetUnitFlyHeight(whichUnit)+LocationZ(.target.x,.target.y)
endif
// - # - - - - - - - - - - - - - # - //
// - # - New Distance Assignment - # - //
set .distanceToMove=vector.difference(.start,.target).length
set .movedDistance=0
// - # - - - - - - - - - - - - - - # - //
// - # - New Speed Assignment - # - //
call .speed.destroy()
set .speed=vector.unitVector(vector.difference(.start,.target))
call .speed.scale(.speedFactor)
call .speed.stopAutoClear()
// - # - - - - - - - - - - - - - # - //
set .alive=true
endif
endmethod
// - # - With this function you can assign the first target unit.
// - # - Requires 1 argument:
// - # - - unit whichUnit: the new target Unit.
// - # - ! Only works befor the missile starts moving for the first time !
method assignTargetUnit takes unit whichUnit returns nothing
if not .inMotion then
// - # - Target Unit Assignment - # - //
set .missileTarget=whichUnit
// - # - - - - - - - - - - - - - # - //
// - # - Target Assignment - # - //
set .target.x=GetUnitX(whichUnit)
set .target.y=GetUnitY(whichUnit)
if GetUnitFlyHeight(whichUnit)==0. then
set .target.z=Missile_DefaultHeight+LocationZ(.target.x,.target.y)
else
set .target.z=GetUnitFlyHeight(whichUnit)+LocationZ(.target.x,.target.y)
endif
// - # - - - - - - - - - - - # - //
// - # - Distance Assignment - # - //
set .distanceToMove=vector.difference(.start,.target).length
// - # - - - - - - - - - - - - # - //
// - # - Speed Assignment - # - //
call .speed.destroy()
set .speed=vector.unitVector(vector.difference(.start,.target))
call .speed.scale(.speedFactor)
call .speed.stopAutoClear()
// - # - - - - - - - - - - - # - //
endif
endmethod
// - # - - - - - - - - - - - - - - - - - - # - //
// - # - Missile Update Functions - # - //
// - # - This function updates the vectors when the target is a Unit
private method updateTargetConditions takes nothing returns nothing
local real d
if .missileTarget!=null then
set d=vector.difference(.position,.target).length
// - # - Target Assignment - # - //
set .target.x=GetUnitX(.missileTarget)
set .target.y=GetUnitY(.missileTarget)
if GetUnitFlyHeight(.missileTarget)==0. then
set .target.z=Missile_DefaultHeight+LocationZ(.target.x,.target.y)
else
set .target.z=GetUnitFlyHeight(.missileTarget)+LocationZ(.target.x,.target.y)
endif
// - # - - - - - - - - - - - # - //
// - # - Distance Assignment - # - //
set d=vector.difference(.position,.target).length-d
set .distanceToMove=.distanceToMove+d
// - # - - - - - - - - - - - - # - //
// - # - Speed Assignment - # - //
call .speed.destroy()
set .speed=vector.unitVector(vector.difference(.position,.target))
call .speed.scale(.speedFactor)
call .speed.stopAutoClear()
// - # - - - - - - - - - - - # - //
endif
endmethod
// - # - This function updates the position vectors x-coordinate and y-coordinate.
private method updatePosition takes nothing returns nothing
if .missileTarget!=null and GetWidgetLife(.missileTarget)<0.405 then
call .clear()
endif
call .position.add(.speed)
set .movedDistance=.movedDistance+.speed.length
endmethod
// - # - This function updates the position to the xy-position. (only if the missile uses a xyArc)
private method updateXY takes nothing returns nothing
local real d=.distanceToMove
local real x=.movedDistance
local real a=vector.difference(.position,.target).xyAngle
if .xyArc!=0. then
set thistype.helper.x=.position.x+ParabolaZ(.xyArc,d,x)*Sin(a)
set thistype.helper.y=.position.y-ParabolaZ(.xyArc,d,x)*Cos(a)
endif
endmethod
// - # - This function updates the position vectors z-coordinate.
private method updateZ takes nothing returns nothing
local real d=.distanceToMove
local real x=.movedDistance
set .position.z=ParabolaZEx(.zArc,d,x,.start.z,.target.z)
endmethod
// - # - This function updates the missiles position.
private method updateDummyPosition takes nothing returns nothing
if .xyArc!=0. then
set .dummy.x=thistype.helper.x
set .dummy.y=thistype.helper.y
else
set .dummy.x=.position.x
set .dummy.y=.position.y
endif
set .dummy.z=.position.z - LocationZ(.dummy.x,.dummy.y)
endmethod
// - # - This function checks whether the target location has been reached.
private method checkTargetConditions takes nothing returns nothing
if .target.isInSphere(.dummy.x,.dummy.y,.dummy.z,Missile_DetectionRange) or .movedDistance>.distanceToMove then
set .alive=false
call .onTargetReach()
if .clearOnTargetReach then
set .inMotion=false
call .clear()
endif
endif
endmethod
// - # - This function checks whether the missile passes a wall.
private method checkForWalls takes nothing returns nothing
if .dummy.z<LocationZ(.dummy.x,.dummy.y) and .hitWalls then
call .onWallHit(.dummy.x,.dummy.y)
endif
endmethod
// - # - This function updates the missiles horizontal facing.
private method updateFacing takes nothing returns nothing
local real d=.distanceToMove
local real x=.movedDistance
local real s=.speed.length
local real z0=ParabolaZ(.xyArc,d,x)
local real z1=ParabolaZ(.xyArc,d,x+s)
local real a=Atan2(z1-z0,s)*-1*degree
if .xyArc!=0 then
set .dummy.facing=a+.speed.xyAngle*degree
else
set .dummy.facing=.speed.xyAngle*degree
endif
endmethod
// - # - This function updates the missiles vertical facing.
private method updateZFacing takes nothing returns nothing
local real d=.distanceToMove
local real x=.movedDistance
local real s=.speed.length
local real z0=ParabolaZEx(.zArc,d,x,.start.z,.target.z)
local real z1=ParabolaZEx(.zArc,d,x+s,.start.z,.target.z)
set .dummy.zfacing=Atan2(z1-z0,s)*degree
endmethod
// - # - - - - - - - - - - - - - - - - - # - //
// - # - Enumeration Functions - # - //
// - # - This function checks for Missile and Unit Collision.
private static method enumFilter takes nothing returns boolean
local thistype temp=thistype.currentInstance
local unit enum=GetFilterUnit()
// - # - Missile Collision Enumeration - # - //
if thistype[enum]!=0 and temp.hitMissiles and not IsUnitInGroup(enum,temp.enumGroup) and vector.vectorInSphere(thistype[enum],temp,Missile_DetectionRange) then
call temp.onMissileHit(thistype[enum])
call GroupAddUnit(temp.enumGroup,enum)
return false
endif
// - # - - - - - - - - - - - - - - - - - # - //
// - # - Unit Collision Enumeration - # - //
if not IsUnitInGroup(enum,temp.enumGroup) then
call GroupAddUnit(temp.enumGroup,enum)
call temp.onUnitHit(enum)
return false
endif
// - # - - - - - - - - - - - - - - - # - //
return false
endmethod
// - # - This function checks for Destructable Collision.
private static method enumDestructables takes nothing returns boolean
call thistype.currentInstance.onDestructableHit(GetFilterDestructable())
return false
endmethod
// - # - - - - - - - - - - - - - - - - - - # //
// - # - Missile Loop Function - # - //
// - # - This function Loops through all missile Instances
private static method callback takes nothing returns nothing
local integer i=1
local thistype temp=0
loop
exitwhen i==thistype.missileCount
if thistype(i).inMotion then
set temp=thistype(i)
// - # - Missile Updating - # - //
call temp.updateTargetConditions()
call temp.updatePosition()
call temp.updateXY()
call temp.updateZ()
call temp.updateDummyPosition()
call temp.checkTargetConditions()
call temp.checkForWalls()
call temp.updateFacing()
call temp.updateZFacing()
// - # - - - - - - - - - - - # - //
// - # - Enumerations - # - //
set thistype.currentInstance=temp
call GroupEnumUnitsInRange(temp.enumGroup,temp.dummy.x,temp.dummy.y,Missile_DetectionRange,Condition(function thistype.enumFilter))
if temp.hitDestructables then
call SetRect(thistype.locRect,temp.dummy.x-Missile_DetectionRange,temp.dummy.y-Missile_DetectionRange,temp.dummy.x+Missile_DetectionRange,temp.dummy.y+Missile_DetectionRange)
call EnumDestructablesInRect(thistype.locRect,Condition(function thistype.enumDestructables),null)
endif
// - # - - - - - - - - - # - //
call temp.onLoop()
endif
set i=i+1
endloop
endmethod
// - # - - - - - - - - - - - - - - - - - # - //
private static method onInit takes nothing returns nothing
set thistype.locRect=Rect(.0,.0,.0,.0)
set thistype.helper=vector.create(.0,.0,.0)
call thistype.helper.stopAutoClear()
call TimerStart(thistype.missileTimer,Missile_TimerPeriod,true,function thistype.callback)
endmethod
endstruct
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//==============================================================================
// TEXT TAG - Floating text system by Cohadar - v5.0
//==============================================================================
//
// PURPOUSE:
// * Displaying floating text - the easy way
// * Has a set of useful and commonly needed texttag functions
//
// CREDITS:
// * DioD - for extracting proper color, fadepoint and lifespan parameters
// for default warcraft texttags (from miscdata.txt)
//
// HOW TO IMPORT:
// * Just create a trigger named TextTag
// convert it to text and replace the whole trigger text with this one
//==============================================================================
library TextTag
globals
// for custom centered texttags
private constant real MEAN_CHAR_WIDTH = 5.5
private constant real MAX_TEXT_SHIFT = 200.0
private constant real DEFAULT_HEIGHT = 16.0
// for default texttags
private constant real SIGN_SHIFT = 16.0
private constant real FONT_SIZE = 0.024
private constant string MISS = "miss"
endglobals
//===========================================================================
// Custom centered texttag on (x,y) position
// color is in default wc3 format, for example "|cFFFFCC00"
//===========================================================================
public function XY takes real x, real y, string text, string color returns nothing
local texttag tt = CreateTextTag()
local real shift = RMinBJ(StringLength(text)*MEAN_CHAR_WIDTH, MAX_TEXT_SHIFT)
call SetTextTagText(tt, color+text, FONT_SIZE)
call SetTextTagPos(tt, x-shift, y, DEFAULT_HEIGHT)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.5)
call SetTextTagLifespan(tt, 4.0)
call SetTextTagPermanent(tt, false)
set tt = null
endfunction
//===========================================================================
// Custom centered texttag above unit
//===========================================================================
function Unit takes unit whichUnit, string text, string color returns nothing
local texttag tt = CreateTextTag()
local real shift = RMinBJ(StringLength(text)*MEAN_CHAR_WIDTH, MAX_TEXT_SHIFT)
call SetTextTagText(tt, color+text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit)-shift, GetUnitY(whichUnit), DEFAULT_HEIGHT)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.5)
call SetTextTagLifespan(tt, 4.0)
call SetTextTagPermanent(tt, false)
set tt = null
endfunction
//===========================================================================
// Standard wc3 gold bounty texttag, displayed only to killing player
//===========================================================================
function GoldBounty takes unit whichUnit, integer bounty, player killer returns nothing
local texttag tt = CreateTextTag()
local string text = "+" + I2S(bounty)
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit)-SIGN_SHIFT, GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 255, 220, 0, 255)
call SetTextTagVelocity(tt, 0.0, 0.03)
call SetTextTagVisibility(tt, GetLocalPlayer()==killer)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 3.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
//==============================================================================
function LumberBounty takes unit whichUnit, integer bounty, player killer returns nothing
local texttag tt = CreateTextTag()
local string text = "+" + I2S(bounty)
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit)-SIGN_SHIFT, GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 0, 200, 80, 255)
call SetTextTagVelocity(tt, 0.0, 0.03)
call SetTextTagVisibility(tt, GetLocalPlayer()==killer)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 3.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
//===========================================================================
function Manaburn takes unit whichUnit, integer dmg returns nothing
local texttag tt = CreateTextTag()
local string text = "-" + I2S(dmg)
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit)-SIGN_SHIFT, GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 82, 82 ,255 ,255)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 5.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
//===========================================================================
function Miss takes unit whichUnit returns nothing
local texttag tt = CreateTextTag()
call SetTextTagText(tt, MISS, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit), GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 255, 0, 0, 255)
call SetTextTagVelocity(tt, 0.0, 0.03)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 1.0)
call SetTextTagLifespan(tt, 3.0)
call SetTextTagPermanent(tt, false)
set tt = null
endfunction
//===========================================================================
function CriticalStrike takes unit whichUnit, integer dmg returns nothing
local texttag tt = CreateTextTag()
local string text = I2S(dmg) + "!"
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit), GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 255, 0, 0, 255)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 5.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
//===========================================================================
function ShadowStrike takes unit whichUnit, integer dmg, boolean initialDamage returns nothing
local texttag tt = CreateTextTag()
local string text = I2S(dmg)
if initialDamage then
set text = text + "!"
endif
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit), GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 160, 255, 0, 255)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 5.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
-
-- ## ## --
-- ## -- # -- ## --
-- ## -- ## --- ## -- ## --
-- ## -- ## ## -- ## --
-- ## -- ChainAbilitySystem v.06 -- ## --
-- ## -- ## ## -- ## --
-- ## -- ## --- ## -- ## --
-- ## -- # -- ## --
-- ## ## --
-
-- # -- by Inferior -- # --
Credits:
Vexorian
Cohader
N-a-z-g-u-l
-- # -- Requirements: -- # --
Table
MissileSystem
-- # -- Documentation: -- # --
- Q: How to import this system?
A: First of all make sure you copy the ChainAbilitySystems code into your map. Then copy all required libraries
into your map. The next step is optional. Since this system uses the MissileSystem you also have to include the
Dummy library. There is a dummy model used in this library. If you want you can use this model. But you can also
use your own dummy unit. The only advantage with the model included in this map is, that you can change the
dummys Z-Facing.
- Q: How does this system work?
A: This System uses a projectile generated by the MissileSystem, which travels from one unit to another.
It allows the user to easily manipulate the projectiles behaviour, easy handling of target enumeration,
ensures leakfree and realistic physics in the projectiles movement and auto-recycling of all
Instances.
- Q: Which features are provided?
A: This System allows you to easily create your own Chaining Abilities like the "Far Seers" Chainlightning.
It allows declaring custom targeting Filters and custom target-manipulation functions.
- Q: How do i create my own Chaining Ability?
A: The best way to answer this question is to provide an example:
First of all you have to declare a new struct like this:
struct YourChainAbilityStruct
The next step is to add 2 methods.
The First method is the target enumeration Filter:
method targetFilter takes nothing returns boolean
Here you can declare a custom enumeration Filter for the Chaining Ability to filter out the correct targets.
I will give further informations after we declared our second method.
! Hint ! : This method has not to be declared, it is optional. If you do not have any Filters just do not declare this method.
The Second method is the target-manipulation function:
method onTargetHit takes nothing returns nothing
Here you can declare whatever shall happen, when a unit is hit by your Chaining Ability.
! Hint ! : This method has to be declared, otherwise your projectile will just move from unit to unit, but have no effect on them.
The next step is the code decleration in those 2 methods.
There are 3 values available to detect the current Target, the casting Unit and the allready hit targets.
All three variables use the prefix: "ChainAbility."
- To detect the current Target you can use this variable: ChainAbility.CurrentTarget
- To detect the casting Unit you can use this variable: ChainAbility.CastingUnit
- To detect the allready hit target amount you can use this variable: ChainAbility.CurrentHit
! Hint ! : These variables only work correctly when used in those 2 methods.
! Hint ! : In the targetFilter method, the ChainAbility.CurrentTarget functions as the GetFilterUnit(),
so use ChainAbility.CurrentTarget instead of GetFilterUnit()
You may add any other struct variables or methods you need for your Chaining Ability, but this has no effect on the main system.
Now that you added the 2 methods you can create your Chaining Ability:
To create a new Chaining Ability Instance you have to use the .create() method:
local YourChainAbilityStruct instance=YourChainAbilityStruct.create()
Now that you have created a new instance of your Chaining Ability, you can manipulate its behaviour:
set instance.missileSpeed = 900 - This changes the Chains projectile speed. Use values like in common Object Editor.
set instance.pickRange = 750 - This sets the AoE in which the projectile will check for new possible targets.
If this is not assigned the instance will be destroyed, when it reachs the first target.
set instance.missileModel = "Units\\...." - This assigns the Chain projectiles Model to the model Path entered.
The Chains projectile has no model by default.
set instance.lightningModel = "MBUR" - This enables the usage of lightnings in the Chain. The entered Path is the
lightnings model type. Lightning usage is disabled by default. Use this to enable it.
set instance.hitCount = 6 - This sets the number of targets that can be hit by the Chaining Ability.
set instance.useZArc = 0.5 - This sets the projectiles zArc, means the parabola curve of the projectile.
Use values like in common Object Editor, e.g. values between 0.0 and 1.0.
set instance.hitMoreThanOnce = true - Assigns whether a Unit can be hit more than one time by the same Chaining Ability.
This is set to false by default.
set instance.moveBackToSource = true - Assigns whether the Chains projectile shall move back to the source Unit when the last target is hit.
This is set to false by default.
When you are done with the movement behaviour manipulation you can start the Chaining Ability.
To start the Chaining Ability you have to use the .Cast() method:
call instance.Cast("for the arguments see 1 line below")
The .Cast() method requires 2 Arguments. The first Argument is the "source". The "source" argument specifies the Chains
Start and Casting/Source Unit (The Unit that sends out the Chain). The second Argument is the "target". The "target" argument
specifies the Unit that gets hit first.
And thats all you have to do...
If there is still something unclear, check the Samples to better understand this system.
- Q: How do lightning and missile work toegher?
A: As you know this system uses a Missile System. The model you assign to the Chains projectile will be created on the Missile
Systems Dummy. A lightning is created as soon as the Missile reaches the currently targeted Unit. If you do not define the Missiles
model, you do not have to worry that lightnings won´t work. A non-assigned Missile model does not mean there is no Missile.
If you want your Chain to only have a lightning, you still have to specify the speed value. The higher the speed value is,
the faster the lightning appears between the last and the new targeted Unit!
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ChainAbilSystem requires MissileSystem, Table
//*************************************************************
//* ChainAbilSystem v.06 by Inferior
//*
//* Requirements:
//*
//* - MissileSystem by Inferior
//*
//* - Table by Vexorian
//*
//* The purpose of this library is to allow easy handling and creation
//* of Custom ChainAbilities like a Chainlightning with your own Effects.
//*
//* The best to understand this is an example:
//*
//* struct YourOwnChainAbility extends ChainAbility
//* "your Structvariables go here".......
//*
//* method targetFilter takes nothing returns boolean
//* return "your Filter".....
//* ! Use ChainAbility.CurrentTarget instead of GetFilterUnit()
//* ! Use ChainAbility.CastingUnit to get the Chains Source
//* ! Use ChainAbility.CurrentHit to get the count of allready hit units
//*
//* !!!! If this method cannot be found in the Childstruct the standard Filter will apply !!!!
//* endmethod
//*
//* method onTargetHit takes nothing returns nothing
//* ! Use ChainAbility.CurrentTarget to get the Unit hit by the Chain
//* ! Use ChainAbility.CastingUnit to get the Chains Source
//* ! Use ChainAbility.CurrentHit to get the count of allready hit units
//* "your code goes here"
//*
//* !!!! If this method cannot be found in the Childstruct nothing will happen when the Chain hits an Unit !!!!
//* endmethod
//*
//* "your other methods go here".......
//* endstruct
//*
//* To create a new Chain use this:
//* !your extending struct!
//* local YourOwnChainAbility data=YourOwnChainAbiltiy.create()
//*
//* To manipulate the Chains behaviour use this:
//* set temp.hitCount="yourHitCount" - Sets the maximal targets the Chain can have
//*
//* set temp.pickRange="yourDetectionRange" - Sets the AoE where the Chain searchs for new Targets
//*
//* set temp.missileModel="yourMissileModelPath" - Sets the missiles Model
//*
//* set temp.lightningModel="yourLightningModelPath" - Sets the Chains Lightning type model
//*
//* set temp.missileSpeed="yourChainSpeed" - Sets the Chains movespeed. Uses common Wc3 object editor speeds. (e.g. 900)
//*
//* set temp.useZArc="yourZArc" - Change the Chains fly behaviour (parabola movement).
//* Uses common Wc3 object editor arcs (e.g. 0.0 to 1.0)
//*
//* set temp.hitMoreThanOnce="yourFlag" - Change the Chains flag, whether the Chain can hit one Unit more than once.
//*
//* set temp.moveBackToSource="yourFlag" - Change the Chains flag, whether the Chain shall move back to the Source, after
//* it hit the last possible Target
//*
//* To Start a Chain use this:
//*
//* call temp.Cast("YourSourceUnit","YourTargetUnit") - This starts the Chain with "YourSourceUnit" as the Chains source and
//* "YourTargetUnit" as the Chains first Target
//*
//***********************************************************
globals
// - # - Lightning Type Model Paths - # - //
constant string AerialShackles = "LEAS"
constant string ChainLightning_Primary = "CLPB"
constant string ChainLightning_Secondary = "CLSB"
constant string DrainLife = "DRAL"
constant string DrainMana = "DRAM"
constant string DrainLifeAndMana = "DRAB"
constant string FingerOfDeath = "AFOD"
constant string ForkedLightning = "FORK"
constant string LightningAttack = "CHIM"
constant string HealingWave_Primary = "HWPB"
constant string HealingWave_Secondary = "HWSB"
constant string ManaBurn = "MBUR"
constant string ManaFlare = "MFPB"
constant string SpiritLink = "SPLK"
// - # - - - - - - - - - - - - - - - - # - //
endglobals
private struct Lightning
// - # - Lightning Data - # - //
//* The lightning variable
private lightning light
// - # - Lightning Targets - # - //
private unit firstEnd //* The First Unit attached to the Lightning
private unit secondEnd //* The Second Unit attached to the Lightning
//* The Height-Offset for each unit
private real fly1=0.
private real fly2=0.
// - # - - - - - - - - - - - # - //
// - # - Fade and Instance - # - //
private boolean visible
private real alpha=1.
// - # - - - - - - - - - - - # - //
// - - - - - - - - - - - - # - //
// - # - Struct Data - # - //
private static integer lightCount=1
private static timer lightTimer=CreateTimer()
// - # - - - - - - - - - - //
// - # - After Lightning completly faded - # - //
private method clear takes nothing returns nothing
call DestroyLightning(.light)
set .firstEnd=null
set .secondEnd=null
set .visible=false
set .alpha=1.
set .fly1=0.
set .fly2=0.
call .destroy()
endmethod
// - # - - - - - - - - - - - - - - - - - - # - //
// - # - Attach Fading Lightning Method - # - //
static method attachBetweenUnits takes unit firstEnd, unit secondEnd, string path returns nothing
local thistype data=thistype.allocate()
if data==thistype.lightCount then
set thistype.lightCount=thistype.lightCount+1
endif
// - # - Check z-coordinate - # - //
if GetUnitFlyHeight(firstEnd)==0 then
set data.fly1=50.
else
set data.fly1=GetUnitFlyHeight(firstEnd)
endif
if GetUnitFlyHeight(secondEnd)==0 then
set data.fly2=50.
else
set data.fly2=GetUnitFlyHeight(secondEnd)
endif
// - # - - - - - - - - - - - - # - //
set data.firstEnd=firstEnd
set data.secondEnd=secondEnd
set data.visible=true
set data.light=AddLightningEx(path,true,GetUnitX(firstEnd),GetUnitY(firstEnd),data.fly1,GetUnitX(secondEnd),GetUnitY(secondEnd),data.fly2)
endmethod
// - # - - - - - - - - - - - - - - - - - - - # - //
// - # - Loop through Lightning Instances - # - //
private static method fadeLightning takes nothing returns nothing
local integer i=1
loop
exitwhen i==thistype.lightCount
if thistype(i).visible then
call MoveLightningEx(thistype(i).light,true,GetUnitX(thistype(i).firstEnd),GetUnitY(thistype(i).firstEnd),thistype(i).fly1,GetUnitX(thistype(i).secondEnd),GetUnitY(thistype(i).secondEnd),thistype(i).fly2)
// - # - Fading Process - # - //
set thistype(i).alpha=thistype(i).alpha-0.03
if thistype(i).alpha<=0. then
call thistype(i).clear()
else
call SetLightningColor(thistype(i).light,1.,1.,1.,thistype(i).alpha)
endif
// - # - - - - - - - - - - # - //
endif
set i=i+1
endloop
endmethod
// - # - - - - - - - - - - - - - - - - - - - - # - //
private static method onInit takes nothing returns nothing
call TimerStart(thistype.lightTimer,0.03,true,function thistype.fadeLightning)
endmethod
endstruct
struct ChainAbility extends Missile
// - # - Chain Ability Instance Variables - # - //
//* the maximal jump count
private integer maxCount = 1
//* the current jump count
private integer curCount = 1
//* the unit that sends out the ChainAbility
private unit sourceUnit = null
//* the range in which possible targets get picked
private real pickUpRange = 0.0
//* the speed the chains missile has
private real mSpeed = 0.0
//* the zArc the chains missile has
private real arc = 0.0
//* the model the chains missile has
private string mdlPath = ""
//* the lightnings path
private string lightPath = ""
//* checks if a unit can be hit another time (requires multiHit enabled)
private HandleTable targetChecker
//* the flag whether a target can be hit more than once
private boolean multiHit = false
//* the flag whether the chain shall move back to the source
private boolean moveBack = false
//* the flag whether the chain uses a lightning or not
private boolean usesLightning = false
//* the temp unit for lightnings
private unit tempLastUnit = null
// - # - - - - - - - - - - - - - - - - - - # - //
// - # - Public Chain Ability Variables - # - //
//* The Unit that sends out the Chain (use this variable in your onTargetHit and targetFilter method)
static unit CastingUnit = null
//* The Unit that currently gets hit by the Chain (use this variable in your onTargetHit and targetFilter method)
static unit CurrentTarget = null
//* This returns how much targets have been hit allready (use this variable in your onTargetHit method)
static integer CurrentHit = 0
// - # - - - - - - - - - - - - - - - - - # - //
// - # - Enumeration Variables - # - //
//* The Enumeration Group
private static group enumGroup = CreateGroup()
//* The Enumeration Instance
private static thistype currentInstance = 0
// - # - - - - - - - - - - - - - # - //
// - # - on Destruction - # - //
private method onDestroy takes nothing returns nothing
set .usesLightning=false
set .moveBack=false
set .multiHit=false
set .mdlPath=""
set .lightPath=""
endmethod
// - # - Initialization Methods - # - //
// - # - With this function you can start a Chain.
// - # - Requires 2 arguments:
// - # - - unit source: the Unit that sends out the Chain
// - # - - unit target: the Unit that gets targeted by the Chain
method Cast takes unit source, unit target returns nothing
call .setMissileStartPosition(GetUnitX(source),GetUnitY(source),GetUnitFlyHeight(source)+50.)
set .modelPath=.mdlPath
set .setZArc=.arc
set .setSpeed=.mSpeed
set .sourceUnit=source
set .tempLastUnit=source
set .targetChecker=HandleTable.create()
call .assignTargetUnit(target)
call .disableOnTargetDestruction()
call .startMotion()
endmethod
// - # - - - - - - - - - - - - - - # - //
// - # - Manipulation Operators - # - //
// - # - With this function you can enable the usage of a lightning
// - # - Requires 1 argument:
// - # - - string path: the lightnings model path
method operator setLightningModel= takes string path returns nothing
set .usesLightning=true
set .lightPath=path
endmethod
// - # - With this function you can set the Chains hitcount.
// - # - Requires 1 argument:
// - # - - integer hits: the new hitcount amount.
method operator hitCount= takes integer hits returns nothing
set .maxCount=hits
set .curCount=hits
endmethod
// - # - With this function you can set the Chains detection range.
// - # - Requires 1 argument:
// - # - - real AoE: the new detection range.
method operator pickRange= takes real AoE returns nothing
set .pickUpRange=AoE
endmethod
// - # - With this function you can set the Chains speed.
// - # - Requires 1 argument:
// - # - - real speed: the new Chain speed.
method operator missileSpeed= takes real speed returns nothing
set .mSpeed=speed
endmethod
// - # - With this function you can set the Chains model.
// - # - Requires 1 argument:
// - # - - string path: the new Chain model.
method operator missileModel= takes string path returns nothing
set .mdlPath=path
endmethod
// - # - With this function you can set the Chains zArc. (makes the Chain fly a parabola curve, use a value between 0.0 and 1.0)
// - # - Requires 1 argument:
// - # - - real arc: the new zArc.
method operator useZArc= takes real arc returns nothing
set .arc=arc
endmethod
// - # - With this function you can assign whether the Chain can hit one target more than once.
// - # - Requires 1 argument:
// - # - - boolean flag: hit one target more than once or not.
method operator hitMoreThanOnce= takes boolean flag returns nothing
set .multiHit=flag
endmethod
// - # - With this function you can assign whether the Chain shall move back to the source.
// - # - Requires 1 argument:
// - # - - boolean flag: move back to source or not.
method operator moveBackToSource= takes boolean flag returns nothing
set .moveBack=flag
endmethod
// - # - - - - - - - - - - - - - - - - - # - //
// - # - Extending Childstruct Methods - # - //
// - # - With this method you can assign your own enumeration Filter.
// - # - ! This method will be replaced by the Extending Childstruct !
// - # - !! If there is no targetFilter method found in the Childstruct only the standard Filter will apply !!
stub method targetFilter takes nothing returns boolean
return true
endmethod
// - # - With this method you can assign what shall happen when a unit gets hit by the Chain
// - # - ! This method will be replaced by the Extending Childstruct !
// - # - !! If there is no onTargetHit method found in the Childstruct there won't happen anything !!
stub method onTargetHit takes nothing returns nothing
endmethod
// - # - !! For more Informations how this works check the samples !! - # - //
// - # - - - - - - - - - - - - - - - - - - # - //
// - # - This function removes a ChainAbility Instance.
// - # - ! A ChainAbility Instance is automatically destroyed when the hitcount expires or no more possible targets can be found !
private method remove takes nothing returns nothing
call .targetChecker.destroy()
call .clear()
call .destroy()
endmethod
// - # - The enumeration function that checks for possible targets.
private static method enumFilter takes nothing returns boolean
local thistype temp=.currentInstance
local unit old=thistype.CurrentTarget
local boolean b
set thistype.CurrentTarget=GetFilterUnit()
set b= temp.targetFilter() and old!=thistype.CurrentTarget and not temp.targetChecker.exists(thistype.CurrentTarget) and GetUnitTypeId(thistype.CurrentTarget)!='face'
set thistype.CurrentTarget=old
return b
endmethod
// - # - The method that will fire when a missile hits a unit.
private method onTargetReach takes nothing returns nothing
set thistype.CastingUnit=.sourceUnit
set thistype.CurrentTarget=.targetUnit
set thistype.CurrentHit=.maxCount-.curCount
set thistype.currentInstance=this
call .onTargetHit()
if .usesLightning then
call Lightning.attachBetweenUnits(.tempLastUnit,.targetUnit,.lightPath)
set .tempLastUnit=.targetUnit
endif
if .sourceUnit==.targetUnit and .moveBack then
call .remove()
return
endif
if not .multiHit then
set .targetChecker[.targetUnit]=this
endif
set .curCount=.curCount-1
if .curCount==0 then
if .moveBack then
call .assignNewTargetUnit(thistype.CastingUnit)
return
else
call .remove()
return
endif
endif
call GroupEnumUnitsInRange(thistype.enumGroup,GetUnitX(.targetUnit),GetUnitY(.targetUnit),.pickUpRange,Condition(function thistype.enumFilter))
set thistype.CurrentTarget=GroupPickRandomUnit(thistype.enumGroup)
if thistype.CurrentTarget==null then
if .moveBack then
set thistype.CurrentTarget=thistype.CastingUnit
else
call .remove()
return
endif
endif
call .assignNewTargetUnit(thistype.CurrentTarget)
call GroupClear(thistype.enumGroup)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ChainManaBurn initializer Init
globals
private constant integer AbilID = 'A000' //* The Spells MainAbility
private constant real reduction = 0.07 //* The reduction per hit
private real array ManaBurned[4]
endglobals
//* Extend your struct with the ChainAbility
struct ChainManaBurn extends ChainAbility
//* Assign your own TargetFilter
//* Use ChainAbility.CurrentTarget instead of FilterUnit()
//* Use ChainAbility.CastingUnit as the Chains source unit
//* ! If this method is not declared in the Childstruct the standard filter will apply !
method targetFilter takes nothing returns boolean
return GetUnitState(ChainAbility.CurrentTarget,UNIT_STATE_MANA)>0. /*
*/ and GetWidgetLife(ChainAbility.CurrentTarget)>0.405 /*
*/ and IsUnitEnemy(ChainAbility.CurrentTarget,GetOwningPlayer(ChainAbility.CastingUnit)) /*
*/ and not IsUnitType(ChainAbility.CurrentTarget,UNIT_TYPE_MAGIC_IMMUNE)
endmethod
//* Assign what shall happen when a unit gets hit by a Chain
//* Use ChainAbility.CurrentTarget as the Unit that gets hit
//* Use ChainAbility.CastingUnit as the Chains source Unit
//* Use ChainAbility.CurrentHit to get the number of allready hit targets
//* ! If this method is not declared in the Childstruct nothing will happen when a unit is hit !
method onTargetHit takes nothing returns nothing
local real mana=GetUnitState(ChainAbility.CurrentTarget,UNIT_STATE_MANA)
local integer level=GetUnitAbilityLevel(ChainAbility.CastingUnit,AbilID)-1
local real burn=ManaBurned[level] - ManaBurned[level]*(1-Pow(1-reduction,ChainAbility.CurrentHit))
if burn>mana then
set burn=mana
endif
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl",ChainAbility.CurrentTarget,"origin"))
call Manaburn(ChainAbility.CurrentTarget,R2I(burn))
call SetUnitState(ChainAbility.CurrentTarget,UNIT_STATE_MANA,mana-burn)
call UnitDamageTarget(ChainAbility.CastingUnit,ChainAbility.CurrentTarget,burn,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
endmethod
//* The Mana burned per level
static method manaBurnSetup takes nothing returns nothing
set ManaBurned[0]=75
set ManaBurned[1]=125
set ManaBurned[2]=175
set ManaBurned[3]=225
endmethod
endstruct
//* The function that fires on SpellCast
private function SpellCast takes nothing returns nothing
local ChainManaBurn object
if GetSpellAbilityId()==AbilID then
//* Your Chain Setup:
//* Create the Chain with the source Unit, the target Unit and the Chains missile model path
set object=ChainManaBurn.create()
//* Change the Chains zArc to your value (makes the chain fly a parabola curve)
set object.useZArc=0.1
//* Change the Chains model
set object.missileModel="Abilities\\Weapons\\BlackKeeperMissile\\BlackKeeperMissile.mdl"
//* Change the Chains Lightning model
set object.setLightningModel=ManaBurn
//* Change the Chains movespeed
set object.missileSpeed=1200
//* Change the Chains detectionrange
set object.pickRange=500
//* Change the flag whether a unit gets hit more than once
set object.hitMoreThanOnce=false
//* Change the flag whether the chain shall move back to the source
set object.moveBackToSource=false
//* Change the Chains hitcount
set object.hitCount=GetUnitAbilityLevel(GetSpellAbilityUnit(),AbilID)+3
//* Start the Chain
call object.Cast(GetSpellAbilityUnit(),GetSpellTargetUnit())
//* End Chain Setup
endif
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
call ChainManaBurn.manaBurnSetup()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t,function SpellCast)
endfunction
endscope
//TESH.scrollpos=33
//TESH.alwaysfold=0
scope LifeAbsorb initializer Init
globals
private constant integer AbilID = 'A001' //* The Spells MainAbility
private real array absorbLife[4]
endglobals
//* Extend your struct with the ChainAbility
struct LifeAbsorb extends ChainAbility
private real lifeAbsorbed=0.
integer level=0
//* Assign your own TargetFilter
//* Use ChainAbility.CurrentTarget instead of FilterUnit()
//* Use ChainAbility.CastingUnit as the Chains source unit
//* ! If this method is not declared in the Childstruct the standard filter will apply !
method targetFilter takes nothing returns boolean
return IsUnitEnemy(ChainAbility.CurrentTarget,GetOwningPlayer(ChainAbility.CastingUnit)) and GetWidgetLife(ChainAbility.CurrentTarget)>0.405
endmethod
//* Assign what shall happen when a unit gets hit by a Chain
//* Use ChainAbility.CurrentTarget as the Unit that gets hit
//* Use ChainAbility.CastingUnit as the Chains source Unit
//* Use ChainAbility.CurrentHit to get the number of allready hit targets
//* ! If this method is not declared in the Childstruct nothing will happen when a unit is hit !
method onTargetHit takes nothing returns nothing
if ChainAbility.CurrentTarget==ChainAbility.CastingUnit then
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl",ChainAbility.CastingUnit,"origin"))
call SetWidgetLife(ChainAbility.CastingUnit,GetWidgetLife(ChainAbility.CastingUnit)+.lifeAbsorbed)
else
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayDamage.mdl",ChainAbility.CurrentTarget,"chest"))
call UnitDamageTarget(ChainAbility.CastingUnit,ChainAbility.CurrentTarget,absorbLife[.level],true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
set .lifeAbsorbed=.lifeAbsorbed+absorbLife[.level]
endif
endmethod
//* The Life absorbed per level
static method lifeAbsorbSetup takes nothing returns nothing
set absorbLife[0]=25.
set absorbLife[1]=35.
set absorbLife[2]=45.
set absorbLife[3]=60.
endmethod
endstruct
//* The function that fires on SpellCast
private function SpellCast takes nothing returns nothing
local LifeAbsorb object
if GetSpellAbilityId()==AbilID then
//* Your Chain Setup:
//* Create the Chain with the source Unit, the target Unit and the Chains missile model path
set object=LifeAbsorb.create()
//* Change the Chains zArc to your value (makes the chain fly a parabola curve)
set object.useZArc=1
//* Change the Chains model
set object.missileModel="Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilMissile.mdl"
//* Change the Chains Lightning model
set object.setLightningModel=DrainLife
//* Change the Chains movespeed
set object.missileSpeed=1400
//* Change the Chains detectionrange
set object.pickRange=750
//* Change the flag whether a unit gets hit more than once
set object.hitMoreThanOnce=false
//* Change the flag whether the chain shall move back to the source
set object.moveBackToSource=true
//* Change the Chains hitcount
set object.hitCount=16
//* Start the Chain
set object.level=GetUnitAbilityLevel(GetSpellAbilityUnit(),AbilID)-1
call object.Cast(GetSpellAbilityUnit(),GetSpellTargetUnit())
//* End Chain Setup
endif
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
call LifeAbsorb.lifeAbsorbSetup()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t,function SpellCast)
endfunction
endscope