- Joined
- Oct 9, 2019
- Messages
- 295
Hello Hive,
I am wondering if there is a way that I can make the attached spell more computationally efficient?
edit: I was using a local varable for the group "g" but I figured destroying it and re-creating it would be wasteful when I can re-use it
Spell:
Lightning System:
Lightning Utils:
Line segment enumeration:
I am wondering if there is a way that I can make the attached spell more computationally efficient?
edit: I was using a local varable for the group "g" but I figured destroying it and re-creating it would be wasteful when I can re-use it
Spell:
JASS:
scope LaserSweep
private struct Missile extends Missiles
static integer AID = 'A008'
static real angleincrement = 9.0
real angle
static real distance = 1200.
real anglecovered
static real anglecoveredmax = 45.
group alreadyhit
Lightning beam
static group g = CreateGroup()
method onFinish takes nothing returns boolean
if UnitAlive(source) and anglecovered < anglecoveredmax then
set angle = angle + angleincrement
set anglecovered = anglecovered + angleincrement
call deflect(GetUnitX(source) + distance * Cos(angle * bj_DEGTORAD),GetUnitY(source) + distance * Sin(angle * bj_DEGTORAD),0)
return false
endif
call DestroyGroup(alreadyhit)
call beam.remove()
return true
endmethod
method onPeriod takes nothing returns boolean
local unit u
call LightningUtils.enumUnits(g, beam, 100.)
loop
set u=FirstOfGroup(g)
exitwhen u==null
if not IsUnitInGroup(u,alreadyhit) and IsUnitEnemy(u, owner) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not BlzIsUnitInvulnerable(u) and UnitAlive(u) and not IsUnitType(u,UNIT_TYPE_STRUCTURE) then
call GroupAddUnit(alreadyhit,u)
call UnitDamageTarget(source, u, damage, false, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
call AddUnitBonusTimed(u,BONUS_ARMOR,-5,30.0)
endif
call GroupRemoveUnit(g,u)
endloop
set beam.targetX = .x
set beam.targetY = .y
return false
endmethod
static method onCast takes nothing returns nothing
local unit c = GetTriggerUnit()
local real x = GetUnitX(c)
local real y = GetUnitY(c)
local real startingangle = GetUnitFacing(c) - (anglecoveredmax / 2)
local real startingx = x + distance * Cos(startingangle * bj_DEGTORAD)
local real startingy = y + distance * Sin(startingangle * bj_DEGTORAD)
local thistype this = thistype.create(startingx, startingy, 50.0, startingx,startingy, 50.0)
set source = c
set owner = GetOwningPlayer(c)
set model = ""
set speed = 1000
set arc = 0.
set curve = 0.
set damage = 150 + (150 * GetUnitAbilityLevel(c,AID))
set .angle = GetUnitFacing(c)
set .anglecovered = 0.
set .beam = Lightning.unitToPoint(c,startingx,startingy,50,50.,false,0.,"DRAM",0)
set .alreadyhit = CreateGroup()
call launch()
set c=null
endmethod
static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(AID, function thistype.onCast)
endmethod
endstruct
endscope
Lightning System:
JASS:
//TESH.scrollpos=75
//TESH.alwaysfold=0
/*
Lightning System v1.03
by Adiktuz
Basically it allows you to easily create timed or un-timed lightning effects
Features:
->You can create lightnings between two points, two unit, or a point and a unit.
->For lightnings attached to a unit, the system automatically updates the lightning
for changes on the unit (like unit position, height etc)
->Specify the height of the lightning
->Create timed-lightnings that get automatically destroyed when their duration is over
->Supports moving points too (but the lightnings are forced to be timed)
->Allows you to add actions that will run when a lightning has ended and during
update (time of which is equal to T32's period)
->Allows you to attach any type of custom data to each instance
Methods available
How to use: call Lightning.methodName(parameters)
unitToPoint takes unit unit1, real x, real y, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
unitToUnit takes unit unit1, unit unit2, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
pointToPoint takes real sourceX, real sourceY,real targetX, real targetY, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
pointToPointEx takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real targetZ, real duration, string leffect, integer eventkey returns thistype
unitToPointEx takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real duration, string leffect, integer eventkey returns thistype
pointToPointExZ takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real sourceCurZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey returns thistype
unitToPointExZ takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey returns thistype
Parameters:
unit unit1 -> unit end of the lightning
unit unit2 -> other unit end of the lightning for the UTU methods
real x,y -> X,Y coordinates of the point end of the lightning for the UTP methods
real sourceX,sourceY -> X,Y coordinates of the first point of the lightning for the PTP methods
real sourceZ,targetZ -> height of the lightning at each ends (actual height is calculated as z + height of unit (if there's a unit end) + locationZ)
real deltaSourceX,deltaSourceY,deltaTargetX,deltaTargetY,sourceCurZ,targetCurZ -> for the Ex and ExZ methods, the final value of each coordinate/height
(the lightning moves from sourceX to deltaSourceX, etc through the given time)
boolean timed -> whether the lightning has a timed life or not, defaulted to true for the Ex and ExZ methods
real duration -> timed life of the lightning
string leffect -> string name of the lightning effect
integer eventkey -> a key used to determine the correct update and end functions to run if available
(if you're not using the update and end events, you're probably saf to just set it to 0)
Note: all of the above methods return the Lightning instance so you can save it in a variable
Extra/Interface/Events:
registerUpdateEvent(integer eventkey, code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning with the
same eventkey as the one registered is updated (every T32_PERIOD)
registerEndEvent(integer eventkey, code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning with the
same eventkey as the one registered ends
NOTE: If you're going to use the next three functions/methods, make sure you set the
corresponding boolean at the globals block to true
registerGlobalUpdateEvent(code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning
is updated (every T32_PERIOD)
registerGlobalEndEvent(code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning ends
registerGlobalCreateEvent(code ToDo) returns nothing
-> allows you to register an action that will be run whenever a lightning is created
To allow creation and usage of custom data that is attached to every instance
turn the boolean USE_CUSTOM_DATA to true
then to add a custom data to an instance:
for integers:
set YourLightningInstance.customData[integer key] = value
for others:
set YourLightningInstance.customData.type[integer key] = value
->type can be real,unit,trigger,effect, etc...
->integer key is the key that will point to the data, you can utilize StringHash if you want to use strings
something like: customData.real[StringHash("damage")]
then to load data:
YourLightningInstance.customData.type[integer key]
To forcefully remove a lightning:
remove() returns nothing
To obtain which lightning instance triggered the events:
instance()
*/
//DO NOT EDIT ANYTHING BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING
//Note: I've set the checkvisibility field to false because the lightnings look
// weird when I set it to true (sometimes they "jump")
library LightningSystem requires T32, Table
globals
//Set this to true if you're gonna use the global update event handler
private constant boolean USE_GLOBAL_UPDATE = false
//Set this to true if you're gonna use the global end event handler
private constant boolean USE_GLOBAL_END = false
//Set this to true if you're gonna use the global create event handler
private constant boolean USE_GLOBAL_CREATE = false
//Set this to true if you're gonna use the custom data feature
private constant boolean USE_CUSTOM_DATA = true
private location loc = Location(0,0)
public Table UpdateTable
public Table EndTable
private trigger globalUpdate
private trigger globalEnd
private trigger globalCreate
endglobals
private module init
static method onInit takes nothing returns nothing
set EndTable = Table.create()
set UpdateTable = Table.create()
static if USE_GLOBAL_UPDATE then
set globalUpdate = CreateTrigger()
endif
static if USE_GLOBAL_END then
set globalEnd = CreateTrigger()
endif
static if USE_GLOBAL_CREATE then
set globalCreate = CreateTrigger()
endif
endmethod
endmodule
struct Lightning extends array
lightning light
real sourceX
real targetX
real sourceY
real targetY
real sourceZ
real targetZ
real sourceZOffset
real targetZOffset
real deltaSourceX
real deltaTargetX
real deltaSourceY
real deltaTargetY
real sourceCurZ
real targetCurZ
real deltaSourceZ
real deltaTargetZ
unit u1
unit u2
integer xtype
boolean timed
boolean moving
real duration
integer eventkey
Table customData
static thistype instance
private static integer instanceCount = 0
private static thistype recycle = 0
private thistype recycleNext
static method registerEndEvent takes integer eventkey, code toDo returns nothing
if not EndTable.handle.has(eventkey) then
set EndTable.trigger[eventkey] = CreateTrigger()
endif
call TriggerAddCondition(EndTable.trigger[eventkey],Filter(toDo))
endmethod
static method registerUpdateEvent takes integer eventkey, code toDo returns nothing
if not UpdateTable.handle.has(eventkey) then
set UpdateTable.trigger[eventkey] = CreateTrigger()
endif
call TriggerAddCondition(UpdateTable.trigger[eventkey],Filter(toDo))
endmethod
static method registerGlobalEndEvent takes code toDo returns nothing
call TriggerAddCondition(globalEnd,Filter(toDo))
endmethod
static method registerGlobalUpdateEvent takes code toDo returns nothing
call TriggerAddCondition(globalUpdate,Filter(toDo))
endmethod
static method registerGlobalCreateEvent takes code toDo returns nothing
call TriggerAddCondition(globalCreate,Filter(toDo))
endmethod
method remove takes nothing returns nothing
call DestroyLightning(this.light)
set instance = this
if EndTable.handle.has(this.eventkey) then
call TriggerEvaluate(EndTable.trigger[this.eventkey])
endif
static if USE_GLOBAL_END then
call TriggerEvaluate(globalEnd)
endif
call this.stopPeriodic()
set this.deltaSourceZ = 0.0
set this.deltaTargetZ = 0.0
set .recycleNext=recycle
set recycle=this
endmethod
static method new takes nothing returns thistype
local thistype this
if (recycle == 0) then
set instanceCount = instanceCount + 1
return instanceCount
else
set this = recycle
set recycle = recycle.recycleNext
endif
return this
endmethod
private method periodic takes nothing returns nothing
if this.xtype == 1 then
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.sourceCurZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
if this.moving then
set this.targetX = this.targetX + this.deltaTargetX
set this.targetY = this.targetY + this.deltaTargetY
endif
if this.deltaTargetZ != 0.0 then
set this.targetZ = this.targetZ + this.deltaTargetZ
endif
set this.targetCurZ = targetZ + this.deltaTargetZ
call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
elseif this.xtype == 2 then
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = GetUnitX(this.u2)
set this.targetY = GetUnitY(this.u2)
set this.sourceCurZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
set this.targetCurZ = targetZOffset + BlzGetLocalUnitZ(this.u2) + GetUnitFlyHeight(this.u2)
call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
else
if this.moving then
set this.sourceX = this.sourceX + this.deltaSourceX
set this.targetX = this.targetX + this.deltaTargetX
set this.sourceY = this.sourceY + this.deltaSourceY
set this.targetY = this.targetY + this.deltaTargetY
if this.deltaSourceZ != 0.0 then
set this.sourceZ = this.sourceZ + this.deltaSourceZ
endif
if this.deltaTargetZ != 0.0 then
set this.targetZ = this.targetZ + this.deltaTargetZ
endif
set this.sourceCurZ = sourceZ + this.deltaSourceZ
set this.targetCurZ = targetZ + this.deltaTargetZ
call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
endif
endif
set instance = this
if UpdateTable.handle.has(this.eventkey) then
call TriggerEvaluate(UpdateTable.trigger[this.eventkey])
endif
static if USE_GLOBAL_UPDATE then
call TriggerEvaluate(globalUpdate)
endif
if this.timed then
set this.duration = this.duration - T32_PERIOD
if this.duration <= 0.0 then
call this.remove()
endif
endif
endmethod
implement T32x
static method unitToPoint takes unit unit1, real x, real y, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = unit1
set this.u2 = null
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = x
set this.targetY = y
set this.sourceZOffset =sourceZ
//call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = timed
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 1
set this.moving = false
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method unitToUnit takes unit unit1, unit unit2, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = unit1
set this.u2 = unit2
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = GetUnitX(this.u2)
set this.targetY = GetUnitY(this.u2)
set this.sourceZOffset =sourceZ
set this.targetZOffset =targetZ
//call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
//call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZOffset + BlzGetLocalUnitZ(this.u2) + GetUnitFlyHeight(this.u2)
set this.timed = timed
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 2
set this.moving = false
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method pointToPoint takes real sourceX, real sourceY,real targetX, real targetY, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = null
set this.u2 = null
set this.sourceX = sourceX
set this.sourceY = sourceY
set this.targetX = targetX
set this.targetY = targetY
call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZ + GetLocationZ(loc)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = timed
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 3
set this.moving = false
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method pointToPointEx takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real targetZ, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = null
set this.u2 = null
set this.sourceX = sourceX
set this.sourceY = sourceY
set this.targetX = targetX
set this.targetY = targetY
set this.deltaSourceX = (deltaSourceX - sourceX)*(T32_PERIOD/duration)
set this.deltaSourceY = (deltaSourceY - sourceY)*(T32_PERIOD/duration)
set this.deltaTargetX = (deltaTargetX - targetX)*(T32_PERIOD/duration)
set this.deltaTargetY = (deltaTargetY - targetY)*(T32_PERIOD/duration)
call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZ + GetLocationZ(loc)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = true
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 3
set this.moving = true
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method unitToPointEx takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = unit1
set this.u2 = null
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = x
set this.targetY = y
set this.sourceZOffset =sourceZ
set this.deltaTargetX = (xx - x)*(T32_PERIOD/duration)
set this.deltaTargetY = (yx - y)*(T32_PERIOD/duration)
//call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = true
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 1
set this.moving = true
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method pointToPointExZ takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real sourceCurZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = null
set this.u2 = null
set this.sourceX = sourceX
set this.sourceY = sourceY
set this.targetX = targetX
set this.targetY = targetY
set this.deltaSourceZ = (sourceCurZ - sourceZ)*(T32_PERIOD/duration)
set this.deltaTargetZ = (targetCurZ-targetZ)*(T32_PERIOD/duration)
set this.deltaSourceX = (deltaSourceX - sourceX)*(T32_PERIOD/duration)
set this.deltaSourceY = (deltaSourceY - sourceY)*(T32_PERIOD/duration)
set this.deltaTargetX = (deltaTargetX - targetX)*(T32_PERIOD/duration)
set this.deltaTargetY = (deltaTargetY - targetY)*(T32_PERIOD/duration)
call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZ + GetLocationZ(loc)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = true
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 3
set this.moving = true
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
static method unitToPointExZ takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey returns thistype
local thistype this = thistype.new()
set this.u1 = unit1
set this.u2 = null
set this.sourceX = GetUnitX(this.u1)
set this.sourceY = GetUnitY(this.u1)
set this.targetX = x
set this.targetY = y
set this.sourceZOffset =sourceZ
set this.deltaTargetZ = (targetCurZ - targetZ)*(T32_PERIOD/duration)
set this.deltaTargetX = (xx - x)*(T32_PERIOD/duration)
set this.deltaTargetY = (yx - y)*(T32_PERIOD/duration)
//call MoveLocation(loc, this.sourceX,this.sourceY)
set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
call MoveLocation(loc, this.targetX,this.targetY)
set this.targetZ = targetZ + GetLocationZ(loc)
set this.timed = true
set this.duration = duration
set this.eventkey = eventkey
set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
set this.xtype = 1
set this.moving = true
static if USE_CUSTOM_DATA then
if this.customData < 0 then
set this.customData = Table.create()
endif
endif
static if USE_GLOBAL_CREATE then
call TriggerEvaluate(globalCreate)
endif
call this.startPeriodic()
return this
endmethod
implement init
endstruct
endlibrary
Lightning Utils:
JASS:
//TESH.scrollpos=114
//TESH.alwaysfold=0
/*
Lightning Utilities v1.01
by Adiktuz
A set of methods that can help you make more out of the
lightning system.
I chose to separate it from the main system because these are
extra methods only to extend the capabilities of the LS.
This way, the user has the option of not using LU library
as the LS will work fine without it.
How to use:
LightningUtils.method(parameters)
Methods:
enumUnits(group g, Lightning light, real radius)
Parameters:
group g -> group that you want to fill with the units between the Lightning's ends
Lightning light -> the Lightning object
real radius -> radius around the Lightning in which unit's will be picked
Note: the following Gradient methods are only for timed lightnings
registerGradientKey(integer eventkey)
->eventkey of the Lightning's that you want to have a color/alpha gradient
Notes:
->it is important that you register first the eventkey using this method
before using the next method which sets the gradient of each Lightning
instance.
->Do this registration only once per eventkey
addLightningGradient(Lightning light, real red1, real blue1, real green1, real alpha1,real red2, real blue2, real green2, real alpha2)
Parameters:
Lightning light -> the Lightning instance that you want to have a gradient
real red1,blue1,green1,alpha1 -> the initial values of the colors/alpha of the Lightning
real red2,blue2,green2,alpha2 -> the final values of the colors/alpha of the Lightning
->these reals are from 0.0 up to 1.0
Notes:
->Make sure that the eventkey used by this Lightning is already registered using the
method above (registerGradientKey)
->This method automatically fetches the duration of the Lightning
->Do not modify the Lightning's duration afterwards else it might look bad
See the Example trigger for an example of how to use these methods.
*/
library LightningUtilities requires LightningSystem
private module init
static method onInit takes nothing returns nothing
set thistype.redTable = Table.create()
set thistype.blueTable = Table.create()
set thistype.greenTable = Table.create()
set thistype.alphaTable = Table.create()
set thistype.redCTable = Table.create()
set thistype.blueCTable = Table.create()
set thistype.greenCTable = Table.create()
set thistype.alphaCTable = Table.create()
endmethod
endmodule
struct LightningUtils extends array
private static group tmpGroup = CreateGroup()
private static unit tmpUnit = null
private static Table redTable
private static Table blueTable
private static Table greenTable
private static Table alphaTable
private static Table redCTable
private static Table blueCTable
private static Table greenCTable
private static Table alphaCTable
static method enumUnits takes group g, Lightning light, real radius returns nothing
call LineSegment.EnumUnitsEx(g,light.sourceX, light.sourceY, light.targetX, light.targetY, radius, true, null)
endmethod
//I used Table to save the RGBA values because if I use the GeLightningColor natives, it returns
//rounded down values, resulting to bad behavior at durations > 4.0
static method updateGradient takes nothing returns nothing
set redCTable.real[Lightning.instance] = redCTable.real[Lightning.instance] + redTable.real[Lightning.instance]
set blueCTable.real[Lightning.instance] = blueCTable.real[Lightning.instance] + blueTable.real[Lightning.instance]
set greenCTable.real[Lightning.instance] = greenCTable.real[Lightning.instance] + greenTable.real[Lightning.instance]
set alphaCTable.real[Lightning.instance] = alphaCTable.real[Lightning.instance] + alphaTable.real[Lightning.instance]
call SetLightningColor(Lightning.instance.light, redCTable.real[Lightning.instance],greenCTable.real[Lightning.instance],blueCTable.real[Lightning.instance],alphaCTable.real[Lightning.instance])
endmethod
static method addLightningGradient takes Lightning light, real red1, real blue1, real green1, real alpha1,real red2, real blue2, real green2, real alpha2 returns nothing
set redCTable.real[light] = red1
set blueCTable.real[light] = blue1
set greenCTable.real[light] = green1
set alphaCTable.real[light] = alpha1
set redTable.real[light] = (((red2-red1)/light.duration)*T32_PERIOD)
set blueTable.real[light] = (((blue2-blue1)/light.duration)*T32_PERIOD)
set greenTable.real[light] = (((green2-green1)/light.duration)*T32_PERIOD)
set alphaTable.real[light] = (((alpha2-alpha1)/light.duration)*T32_PERIOD)
endmethod
static method registerGradientKey takes integer eventkey returns nothing
call Lightning.registerUpdateEvent(eventkey,function thistype.updateGradient)
endmethod
implement init
endstruct
endlibrary
Line segment enumeration:
JASS:
library LineSegmentEnumeration /* v2.2b -- hiveworkshop.com/threads/line-segment-enumeration-v1-1.286552/
Information
¯¯¯¯¯¯¯¯¯¯¯
Allows to enumerate widgets inside a line segment with an offset.
So basicly it will result in a rect, but which is also allowed to be rotated.
Mechanics
¯¯¯¯¯¯¯¯¯
(Issue:)
The problem with normal jass rects is that they aren't defined by 4 points, but only by 4 values: x/y -min/max.
The result is that a jass rect is never rotated, so it's always paralel to the x/y axis.
But when we draw a line from point A to point B we might also create a non-axix-parelel rect, and then
we can't use the normal rect natives from jass anymore to find out if a point is inside the rect.
(Solution:)
To solve this problem the system does following:
jass rect: rectangular defined by 4 values (axis paralel)
custom rect: the real rectangular that is defined by user (not axis parelel)
1. Create a big jass rect that is big enough so we can ensure to enum all widgets that are potentialy inside our custom rect. (Enum_Group)
This Enum_Group will contain all wanted units, but may also contain not wanted units.
2. Construct the custom rect following a form with the same parameters as in this image, but in 2D:
https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Ellipsoide.svg/800px-Ellipsoide.svg.png
3. Loop through Enum_Group and define each widget's coordinates relative to the center of the custom rect as a 2D vector
4. Get the components of the widget's position vector on the local (rotated) x-y axis of the custom rect
5. Check if the projected lengths (absolute value of components) of the widget's position is less than <a> and <b> as described in the
image linked above.
*/
// --- API ---
//! novjass
struct LineSegment
static constant real MAX_UNIT_COLLISION
static method EnumUnitsEx takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolean checkCollision, boolexpr filter returns nothing
static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolexpr filter returns nothing
static method EnumDestructables takes real ax, real ay, real bx, real by, real offset returns nothing
// after enumerated destructables you have access to:
static integer DestructableCounter // starts with index "0"
static destructable array Destructable
static method EnumItems takes real ax, real ay, real bx, real by, real offset returns nothing
// after enumerated items you have access to:
static integer ItemCounter // starts with index "0"
static destructable array Item
//! endnovjass
// ==== End API ====
struct LineSegment extends array
public static constant real MAX_UNIT_COLLISION = 197.00
private static constant rect RECT = Rect(0, 0, 0, 0)
private static constant group GROUP = CreateGroup()
private static real ox
private static real oy
private static real dx
private static real dy
private static real da
private static real db
private static real ui
private static real uj
private static real wdx
private static real wdy
private static method PrepareRect takes real ax, real ay, real bx, real by, real offset, real offsetCollision returns nothing
local real maxX
local real maxY
local real minX
local real minY
// get center coordinates of rectangle
set ox = 0.5*(ax + bx)
set oy = 0.5*(ay + by)
// get rectangle major axis as vector
set dx = 0.5*(bx - ax)
set dy = 0.5*(by - ay)
// get half of rectangle length (da) and height (db)
set da = SquareRoot(dx*dx + dy*dy)
set db = offset
// get unit vector of the major axis
set ui = dx/da
set uj = dy/da
// Prepare the bounding Jass Rect
set offset = offset + offsetCollision
if ax > bx then
set maxX = ax + offset
set minX = bx - offset
else
set maxX = bx + offset
set minX = ax - offset
endif
if ay > by then
set maxY = ay + offset
set minY = by - offset
else
set maxY = by + offset
set minY = ay - offset
endif
call SetRect(RECT, minX, minY, maxX, maxY)
endmethod
private static method RotateWidgetCoordinates takes widget w returns nothing
// distance of widget from rectangle center in vector form
set wdx = GetWidgetX(w) - ox
set wdy = GetWidgetY(w) - oy
set dx = wdx*ui + wdy*uj // get the component of above vector in the rect's major axis
set dy = wdx*(-uj) + wdy*ui // get the component of above vector in the rect's transverse axis
endmethod
private static method IsWidgetInRect takes widget w returns boolean
call RotateWidgetCoordinates(w)
// Check if the components above are less than half the length and height of the rectangle
// (Square them to compare absolute values)
return dx*dx <= da*da and dy*dy <= db*db
endmethod
private static method IsUnitInRect takes unit u, boolean checkCollision returns boolean
if checkCollision then
call RotateWidgetCoordinates(u)
// Check if the perpendicular distances of the unit from both axes of the rect are less than
// da and db
return IsUnitInRangeXY(u, ox - dy*uj, oy + dy*ui, RAbsBJ(da)) /*
*/ and IsUnitInRangeXY(u, ox + dx*ui, oy + dx*uj, RAbsBJ(db))
endif
return IsWidgetInRect(u)
endmethod
public static method EnumUnitsEx takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolean checkCollision, boolexpr filter returns nothing
local unit u
if checkCollision then
call PrepareRect(ax, ay, bx, by, offset, MAX_UNIT_COLLISION)
else
call PrepareRect(ax, ay, bx, by, offset, 0.00)
endif
call GroupEnumUnitsInRect(GROUP, RECT, filter)
// enum through all tracked units, and check if it's inside bounds
call GroupClear(whichgroup)
loop
set u = FirstOfGroup(GROUP)
exitwhen u == null
if IsUnitInRect(u, checkCollision) then
call GroupAddUnit(whichgroup, u)
endif
call GroupRemoveUnit(GROUP, u)
endloop
endmethod
public static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolexpr filter returns nothing
call EnumUnitsEx(whichgroup, ax, ay, bx, by, offset, false, filter)
endmethod
//! textmacro LSE_WIDGET takes TYPE, NAME
public static integer $NAME$Counter = -1
public static $TYPE$ array $NAME$
private static method on$NAME$Filter takes nothing returns nothing
local $TYPE$ t = GetFilter$NAME$()
if IsWidgetInRect(t) then
set $NAME$Counter = $NAME$Counter + 1
set $NAME$[$NAME$Counter] = t
endif
set t = null
endmethod
public static method Enum$NAME$s takes real ax, real ay, real bx, real by, real offset returns nothing
call PrepareRect(ax, ay, bx, by, offset, 0.00)
set $NAME$Counter = -1
call Enum$NAME$sInRect(RECT, Filter(function thistype.on$NAME$Filter), null)
endmethod
//! endtextmacro
//! runtextmacro LSE_WIDGET("destructable", "Destructable")
//! runtextmacro LSE_WIDGET("item", "Item")
endstruct
endlibrary