library Lightning requires optional ARGB
//******************************************************************************
//* Author: Fledermaus
//* Version: 1.02
//*
//* This library is intended to replace the native lightning type.
//* It uses a Lightning struct to provide better functionality (and a nicer
//* syntax if you're that way inclined).
//*
//******************************************************************************
//*
//* Configuration constants that you can alter however you like:
//*
//* TIMEOUT is the timer speed for updating the position of lightning and
//* the alpha for fading in/out.
//*
//******************************************************************************
//*
//* List of methods:
//*
//* static method create takes string codeName, boolean checkVisibility, real fadeTime returns Lightning
//*
//* Creates a new Lightning for you to use.
//* - codeName: Determines what the Lightning looks like. I'm even so nice as
//* to include a constant list of them in the global constant section for
//* you!
//* - checkVisibility: As with normal lightning, this determines if a player
//* needs to have vision of the Lightning (start or end point/unit) in
//* order to see it. If set to true, the Lightning becomes invisible when
//* players lose vision of it.
//* - fadeTime: Makes the Lightning fade into existence. A value of 0 is an
//* instant fade in.
//* Note that it wont initially be attached to anything, that's where the next
//* two methods come in:
//*
//*
//* method attachToPoint takes boolean atStart, real x, real y, real z, boolean considerTerrain returns boolean
//* method attachToUnit takes boolean atStart, unit u, real zOffset returns boolean
//*
//* They should be pretty self-explanatory, they attach the Lightning to either
//* the startPoint or startUnit, or the endPoint or endUnit.
//* The two constants LIGHTNING_START and LIGHTNING_END can be used here to
//* help make your code easier to read.
//* Lightning attached to a unit(s) will follow it around.
//* The boolean considerTerrain in attachToPoint determines if the z value is
//* measured from the terrain or an absolute value.
//* If you don't attach to both a start and end point/unit, the Lightning will
//* connect to 0, 0. So you should attach to both as soon as it's created.
//*
//*
//* method recolor takes real r, real g, real b, real a returns boolean
//* method ARGBrecolor takes ARGB color returns nothing
//* method operator color= takes ARGB color returns nothing
//*
//* Used to set the colour of Lightning. Should only use values between 0.00
//* and 1.00.
//* ARGBrecolor and color= will obviously only work if you have ARGB.
//*
//*
//* method operator red takes nothing returns real
//* method operator green takes nothing returns real
//* method operator blue takes nothing returns real
//* method operator alpha takes nothing returns real
//* method operator color takes nothing returns ARGB
//*
//* Method operators to get the colour components of the Lightning. Pretty
//* self explanatory.
//* Again, color will only work if you have ARGB.
//*
//*
//* method destroy takes nothing returns nothing
//* method release takes real fadeTime returns nothing
//* method releaseDelayed takes real delay, real fadeTime returns nothing
//*
//* Again, pretty self explanatory. destroy will dispose of a Lightning
//* instantly, while release will fade it out over time. releaseDelayed lets
//* you release it after a delay.
//*
//******************************************************************************
//*
//* There is the inherent limit that you can only have 8191 Lightning at once.
//* However, if you ever get this high, your map will have worse problems than
//* this system working improperly.
//*
//******************************************************************************
//*
//* Credits: Thanks to Vexorian for ARGB and vJass. Kueken for the work he
//* previously did which helped me create this library. Anitarf for
//* motivating me to update it and helping me with some of the
//* ideas. Oh and Dusk for being sexy ;)
//*
//* If you have any further questions regarding Lightning or how to use it,
//* feel free to visit [url=http://www.wc3c.net]www.wc3c.net[/url] and ask questions there. This library should
//* only ever be released at WC3C and at no other site. Please give credits if
//* this library finds its way into your maps, and otherwise thanks for reading!
//*
globals
private constant real TIMEOUT = 0.03125
//32 fps
//* Do not edit below here
//Lightning type constants
constant string LIGHTNING_AERIAL_SHACKLES =
"LEAS" constant string LIGHTNING_CHAIN_LIGHTNING_PRIMARY =
"CLPB" constant string LIGHTNING_CHAIN_LIGHTNING_SECONDARY =
"CLSB" constant string LIGHTNING_DRAIN_LIFE =
"DRAL" constant string LIGHTNING_DRAIN_LIFE_AND_MANA =
"DRAB" constant string LIGHTNING_DRAIN_MANA =
"DRAM" constant string LIGHTNING_FINGER_OF_DEATH =
"AFOD" constant string LIGHTNING_FORKED_LIGHTNING =
"FORK" constant string LIGHTNING_HEALING_WAVE_PRIMARY =
"HWPB" constant string LIGHTNING_HEALING_WAVE_SECONDARY =
"HWSB" constant string LIGHTNING_LIGHTNING_ATTACK =
"CHIM" constant string LIGHTNING_MANA_BURN =
"MBUR" constant string LIGHTNING_MANA_FLARE =
"MFPB" constant string LIGHTNING_SPIRIT_LINK =
"SPLK" constant boolean LIGHTNING_START =
true constant boolean LIGHTNING_END =
false
private Lightning array Array
endglobals
//! textmacro LightningDebugTextmacro takes TYPE, RETURN
if .released then
debug call BJDebugMsg(
SCOPE_PREFIX +
" Error: Trying to $TYPE$ a lightning that is fading out of existance")
return $RETURN$
endif
//! endtextmacro
//! textmacro LightningRecolourDebugTextmacro takes VARIABLE, COLOUR
if $VARIABLE$ < 0. then
debug call BJDebugMsg(
SCOPE_PREFIX +
" Error: $COLOUR$ value passed to recolor is less than 0.")
set $VARIABLE$ = 0.
elseif $VARIABLE$ > 1. then
debug call BJDebugMsg(
SCOPE_PREFIX +
" Error: $COLOUR$ value passed to recolor is greater than 1.")
set $VARIABLE$ = 1.
endif
//! endtextmacro
//******************************************************************************
struct Lightning
private real startZOffset
private real fadingAlphaInc
private real releaseDelay
private static method Update takes nothing returns nothing
local Lightning l
loop
exitwhen i >= Index
set l = Array[i]
if l.updatePosition then
//Update the lightning's position if it's attached to a unit
endif
endif
//Check if the lightning can be seen (will locally change the variable for each player)
if l.canSee then
//If it can be seen, make sure you change the alpha back to l.alpha
//because this could have been the first time it's visiable again
set a = l.alphaColour
else
//Otherwise make the alpha 0 so it's invisiable
set a = 0.
endif
//Check if the lightning has been delay released
if l.releaseDelay > 0. and not l.released then
//Count down the delay
set l.releaseDelay = l.releaseDelay - TIMEOUT
if l.releaseDelay <= 0. then
//Time to release it
set l.released = true
if l.fadingAlphaInc < 1. then
//Increase the fadingAlpha by fadingAlphaInc to account for this cycle
set l.fadingAlpha = 1. + l.fadingAlphaInc
else
//If the fade time from the delayed release was 0., release it instantly
set l.fadingAlpha = 0.
endif
endif
endif
if l.released then
if l.fadingAlpha > 0. then
//Lightning is still fading out
set l.fadingAlpha = l.fadingAlpha - l.fadingAlphaInc
if l.fadingAlpha < 0. then
set l.fadingAlpha = 0.
endif
set a = a * l.fadingAlpha
else
//Lightning has finished fading out and should be destroyed
set l.startUnit = null
set l.endUnit = null
call l.deallocate()
set Index = Index - 1
if Index > 0 then
set Array[i] = Array[Index]
set i = i - 1
else
endif
endif
elseif l.fadingAlpha < 1. then
//Lightning is fading in
set l.fadingAlpha = l.fadingAlpha + l.fadingAlphaInc
if l.fadingAlpha >= 1. then
set l.fadingAlpha = 1.
//Check if we need to keep updating the lightning
set l.updatePosition = l.checkVisibility or l.startUnit != null or l.endUnit != null or l.releaseDelay > 0.
if not l.updatePosition then
set Index = Index - 1
if Index > 0 then
set Array[i] = Array[Index]
set i = i - 1
else
endif
endif
endif
set a = a * l.fadingAlpha
endif
//If the lightning still exists, update it's alpha value
endif
set i = i + 1
else
set Index = Index - 1
if Index > 0 then
set Array[i] = Array[Index]
else
endif
endif
endloop
endmethod
static method create takes string codeName,
boolean checkVisibility,
real fadeTime
returns Lightning
local Lightning this = Lightning.allocate()
set .checkVisibility = checkVisibility
set .updatePosition = checkVisibility or fadeTime > 0.
set .released = false
set .canSee = true
//The lightning needs to first be create so that noone can see it but without checking that players
//can see it (checkVisibitiy set to false and at (0, 0) (0, 0)) so that it will not be null for
//players that cannot see it as it's created. It can then be moved to the correct location and have
//the proper visibility setting.
set .startSet = false
set .endSet = false
set .releaseDelay = 0.
if fadeTime > 0. then
set .fadingAlpha = 0.
set .fadingAlphaInc = TIMEOUT / fadeTime
else
debug if fadeTime != 0. then
debug call BJDebugMsg(
SCOPE_PREFIX +
" Error: Trying to create a lightning with a negative fade time")
debug endif
set .fadingAlpha = 1.
endif
if .updatePosition then
if Index == 0 then
call TimerStart(Timer, TIMEOUT,
true,
function Lightning.Update)
endif
set Array[Index] = this
set Index = Index + 1
endif
return this
endmethod
//! runtextmacro LightningDebugTextmacro("change the attached point of", "false")
if atStart then
set .startUnit = null
set .startX = x
set .startY = y
if considerTerrain then
else
set .startZ = z
endif
set .startSet = true
else
set .endUnit = null
set .endX = x
set .endY = y
if considerTerrain then
else
set .endZ = z
endif
set .endSet = true
endif
if .startSet and .endSet then
endif
if .updatePosition and not .checkVisibility and .fadingAlpha == 1. and .startUnit == null and .endUnit == null and .releaseDelay <= 0. then
set .updatePosition = false
endif
return true
endmethod
//! runtextmacro LightningDebugTextmacro("change the attached unit of", "false")
if atStart then
set .startUnit = u
set .startZOffset = zOffset
set .startSet = true
if u != null then
endif
else
set .endUnit = u
set .endZOffset = zOffset
set .endSet = true
if u != null then
endif
endif
if .startSet and .endSet then
endif
if .updatePosition == false then
if Index == 0 then
call TimerStart(Timer, TIMEOUT,
true,
function Lightning.Update)
endif
set Array[Index] = this
set Index = Index + 1
set .updatePosition = true
endif
return true
endmethod
method operator red
takes nothing returns real return .redColour
endmethod
method operator green
takes nothing returns real return .greenColour
endmethod
method operator blue
takes nothing returns real return .blueColour
endmethod
method operator alpha
takes nothing returns real return .alphaColour
endmethod
//! runtextmacro LightningDebugTextmacro("recolor", "false")
//! runtextmacro LightningRecolourDebugTextmacro("r", "red")
//! runtextmacro LightningRecolourDebugTextmacro("g", "green")
//! runtextmacro LightningRecolourDebugTextmacro("b", "blue")
//! runtextmacro LightningRecolourDebugTextmacro("a", "alpha")
set .redColour = r
set .greenColour = g
set .blueColour = b
set .alphaColour = a
if .canSee == false then
set a = 0.
endif
endmethod
static if LIBRARY_ARGB then
method ARGBrecolor takes ARGB color returns nothing
if col < 0 then
set col = -(-col + 0x80000000)
set a = 0x80 + col / 0x1000000
set col = col - (a - 0x80) * 0x1000000
else
set a = col / 0x1000000
set col = col - a * 0x1000000
endif
set r = col / 0x10000
set col = col - r * 0x10000
set g = col / 0x100
set b = col - g * 0x100
set .redColour =
I2R(r) / 255.
set .greenColour =
I2R(g) / 255.
set .blueColour =
I2R(b) / 255.
set .alphaColour =
I2R(a) / 255.
if .canSee then
set alpha = .alphaColour
else
set alpha = 0.
endif
endmethod
method operator color takes nothing returns ARGB
return ARGB.
create(
R2I(.alphaColour * 255.),
R2I(.redColour * 255.),
R2I(.blueColour * 255.),
R2I(.greenColour * 255.))
endmethod
method operator color= takes ARGB color returns nothing
call .ARGBrecolor(color)
endmethod
endif
method release
takes real fadeTime
returns nothing //! runtextmacro LightningDebugTextmacro("release", "")
if fadeTime < 0. then
debug call BJDebugMsg(
SCOPE_PREFIX +
" Error: Trying to release a lightning with a negative fade time")
set fadeTime = 0.
endif
set .released = true
if fadeTime > 0. then
set .fadingAlpha = 1.
set .fadingAlphaInc = TIMEOUT / fadeTime
//Add it to the Update Loop if it's not already in there
if not .updatePosition then
if Index == 0 then
call TimerStart(Timer, TIMEOUT,
true,
function Lightning.Update)
endif
set Array[Index] = this
set Index = Index + 1
set .updatePosition = true
endif
elseif .updatePosition then
//It's already updating so just make it invisible now and it'll get cleaned up in the next loop
set .fadingAlpha = 0.
else
//It's not updating so it can be cleaned up now
set .startUnit = null
set .endUnit = null
call .deallocate()
endif
endmethod
method destroy takes nothing returns nothing
call .release(0.)
endmethod
method releaseDelayed
takes real delay,
real fadeTime
returns nothing //! runtextmacro LightningDebugTextmacro("delayed release", "")
if delay <= 0. then
debug call BJDebugMsg(
SCOPE_PREFIX +
" Error: Trying to delayed release a lightning with a delay not greater than 0.")
set delay = 0.01
endif
if fadeTime < 0. then
debug call BJDebugMsg(
SCOPE_PREFIX +
" Error: Trying to delayed release a lightning with a negative fade time")
set fadeTime = 0.
endif
set .releaseDelay = delay
if fadeTime > 0. then
set .fadingAlphaInc = TIMEOUT / fadeTime
else
//Don't want to divide by 0!
set .fadingAlphaInc = 1.
endif
//Add it to the Update Loop if it's not already in there
if not .updatePosition then
if Index == 0 then
call TimerStart(Timer, TIMEOUT,
true,
function Lightning.Update)
endif
set Array[Index] = this
set Index = Index + 1
set .updatePosition = true
endif
endmethod
endstruct
endlibrary