- Joined
- Nov 7, 2014
- Messages
- 571
Lightning - tries to simplify the usage of the native type lightning
lightning.j:
lightning.j:
JASS:
library Lightning
//! novjass
// References:
// introduction to lightnings: http://www.hiveworkshop.com/threads/beginners-guide-to-lightning-effects.220370/
// customizing lightnings: http://www.hiveworkshop.com/threads/how-to-customise-lightning-effects.203171/
// About:
// The Lightning library tries to simplify using the native type lightning with other native types (units, items, rects, etc.).
// Introduction:
// Each Lightning instance has two ends, a SRC (source, where the lightning originates from) end and
// a DEST (destination, where the lightning "goes to") end. Both of those must be configured before
// the Lightning can be used. The two ends can be linked/connected to different types of objects but
// in order for the Lightning to be properly configured/constructed both ends must be linked/connected to something.
// API:
// creating/configuring
//
// in order to properly create a Lightning we have to open a configure "block"
static method begin_configure takes Lightning_Type lightning_type returns thistype
// where Lightning_Type can be one of the following:
// NOTE: these are the built-in lightning types that are unique, GUI has 4 more but they use the same texture as one of these:
//
Lightning_Type.LIGHTNING
Lightning_Type.DRAIN_LIFE
Lightning_Type.DRAIN_MANA
Lightning_Type.FINGER_OF_DEATH
Lightning_Type.FORKED_LIGHTNING
Lightning_Type.HEALING_WAVE
Lightning_Type.MAGIC_LEASH
Lightning_Type.MANA_BURN
Lightning_Type.MANA_FLARE
Lightning_Type.SPIRIT_LINK
// e.g:
set li = Lightning.begin_configure(Lightning_Type.FINGER_OF_DEATH)
// in the configure "block" we need to set/link both ends of the Lightning to something:
method set_end_xyz takes Lightning_End end, real x, real y, real z returns nothing
method set_end_location takes Lightning_End end, location l returns nothing
method set_end_unit takes Lightning_End end, unit u returns nothing
method set_end_item takes Lightning_End end, item it returns nothing
method set_end_destructable takes Lightning_End end, destructable d returns nothing
method set_end_rect takes Lightning_End end, rect r, Lightning_Rect_Point rp returns nothing
method set_end_camera takes Lightning_End end, camerasetup camera returns nothing // reference: http://www.hiveworkshop.com/threads/using-3d-points-within-world-editor.287597/
method set_end_lightning takes Lightning_End own_end, Lightning other, Lightning_End other_end returns nothing
// where Lightning_End can be one of the following:
Lightning_End.SRC
Lightning_End.DEST
// and Lightning_Rect_Point can be one of the following:
Lightning_Rect_Point.TOP_LEFT
Lightning_Rect_Point.TOP_RIGHT
Lightning_Rect_Point.BOTTOM_RIGHT
Lightning_Rect_Point.BOTTOM_LEFT
Lightning_Rect_Point.CENTER
// e.g:
call li.set_end_xyz(Lightning_End.SRC, 128.0, 256.0, 512.0)
call li.set_end_unit(Lightning_End.DEST, <some-unit>)
// after we've set both ends we have to "close/end the configure block"
method end_configure takes nothing returns nothing
// using the Lightning
//
// moves the Lightning to the positions determined by it's ends
method move takes nothing returns nothing
// for some types like destructable we can't get their height/z but we can make one up:
set li.src_z_offset = 80.0
set li.dest_z_offset = 96.0
// an end can be set to automatically "follow" the object it has been linked to
// NOTE: does not work for ends configured with set_end_xyz
method follow_through_time takes Lightning_End end, boolean flag returns nothing
// set's the color of the Lightning
// the format for the color is: AARRGGBB, e.g: blue = 0xFF0000FF
method set_color takes integer color returns nothing
// linearly transitions the color of the Lightning from start_color to end_color in dur number of seconds
method animate takes integer start_color, integer end_color, real dur returns nothing
// adds a duration to the Lightning, after dur number of seconds the Lightning will be automatically destroyed
method timed takes real dur returns nothing
// destroying
//
// destroyes the Lightning
// NOTE: the wrapped native lightning is not actually destroyed, it get's recycled (moved to "safe haven")
method destroy takes nothing returns nothing
// changing type
//
// changes the type of the Lightning to new_type
// NOTE: this method requires reassignment
method change_type takes Lightning_Type new_type returns thistype
// e.g:
set li = li.change_type(Lightning_Type.SPIRIT_LINK)
//! endnovjass
globals
private constant real CDT = 1.0 / 20.0 // color update period (every 20th of a second)
private constant real PDT = 1.0 / 32.0 // position update period
// where lightnings are moved when they are recycled
private constant real SAFE_HAVEN_X = -2147483648
private constant real SAFE_HAVEN_Y = -2147483648
private constant real SAFE_HAVEN_Z = -2147483648
endglobals
// for timed lightnings
private struct Timer extends array
readonly static integer max_count = 0
private static Timer head = 0 // a free list of timers
private Timer next
private timer t
integer data
real timeout
static method start takes integer user_data, real timeout, code callback returns Timer
local Timer this
if head != 0 then
set this = head
set head = head.next
else
set max_count = max_count + 1
if max_count > 8190 then
static if DEBUG_MODE then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "|cffFF0000[Lightning::Timer] error: could not allocate a Timer instance|r")
endif
return 0
endif
set this = max_count
set this.t = CreateTimer()
endif
set this.next = 0
set this.data = user_data
set this.timeout = timeout
call TimerStart(this.t, this, false, null)
call PauseTimer(this.t)
call TimerStart(this.t, timeout, false, callback)
return this
endmethod
method stop takes nothing returns nothing
if this == 0 then
static if DEBUG_MODE then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "|cffFF0000[Lightning::Timer] error: cannot stop null Timer instance|r")
endif
return
endif
if this.next != 0 then
static if DEBUG_MODE then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "|cffFF0000[Lightning::Timer] error: cannot stop Timer(" + I2S(this) + ") instance more than once|r")
endif
return
endif
call TimerStart(this.t, 0.0, false, null)
set this.next = head
set head = this
endmethod
static method get_expired_data takes nothing returns integer
local Timer t = Timer( R2I(TimerGetRemaining(GetExpiredTimer()) + 0.5) )
local integer data = t.data
call t.stop()
return data
endmethod
endstruct
/*enum*/ struct Lightning_Type extends array
// vJass does not allow:
// static constant thistype FOO = 42 // error: constant structs are not supported
// so we use readonly instead
//
readonly static thistype LIGHTNING = 1
readonly static thistype DRAIN_LIFE = 2
readonly static thistype DRAIN_MANA = 3
readonly static thistype FINGER_OF_DEATH = 4
readonly static thistype FORKED_LIGHTNING = 5
readonly static thistype HEALING_WAVE = 6
readonly static thistype MAGIC_LEASH = 7
readonly static thistype MANA_BURN = 8
readonly static thistype MANA_FLARE = 9
readonly static thistype SPIRIT_LINK = 10
static constant integer COUNT = 10
private static string array ids
private static string array names
private static method onInit takes nothing returns nothing
set ids[LIGHTNING] = "CHIM"
set names[LIGHTNING] = "Lightning"
set ids[DRAIN_LIFE] = "DRAL"
set names[DRAIN_LIFE] = "Drain Life"
set ids[DRAIN_MANA] = "DRAM"
set names[DRAIN_MANA] = "Drain Mana"
set ids[FINGER_OF_DEATH] = "AFOD"
set names[FINGER_OF_DEATH] = "Figner of Death"
set ids[FORKED_LIGHTNING] = "FORK"
set names[FORKED_LIGHTNING] = "Forked Lightning"
set ids[HEALING_WAVE] = "HWPB"
set names[HEALING_WAVE] = "Healing Wave - Primary"
set ids[MAGIC_LEASH] = "LEAS"
set names[MAGIC_LEASH] = "Magic Leash"
set ids[MANA_BURN] = "MBUR"
set names[MANA_BURN] = "Mana Burn"
set ids[MANA_FLARE] = "MFPB"
set names[MANA_FLARE] = "Mana Flare"
set ids[SPIRIT_LINK] = "SPLK"
set names[SPIRIT_LINK] = "Spirit Link"
endmethod
method to_id takes nothing returns string
return ids[this]
endmethod
method to_str takes nothing returns string
return names[this]
endmethod
endstruct
// /*enum*/ struct Lightning_Visibility extends array
// static constant boolean VISIBLE_THROUGH_FOG = false
// static constant boolean INVISIBLE_THROUGH_FOG = true
// endstruct
/*enum*/ struct Lightning_End extends array
static constant integer SRC = 1
static constant integer DEST = 2
endstruct
/*enum*/ struct Lightning_Link extends array
static constant integer UNDEFINED = 0
static constant integer XYZ = 1
static constant integer LOCATION = 2
static constant integer UNIT = 3
static constant integer ITEM = 4
static constant integer DESTRUCTABLE = 5
static constant integer RECT = 6
static constant integer CAMERA = 7
static constant integer LIGHTNING = 8
endstruct
/*enum*/ struct Lightning_Rect_Point extends array
static constant integer TOP_LEFT = 1
static constant integer TOP_RIGHT = 2
static constant integer BOTTOM_RIGHT = 3
static constant integer BOTTOM_LEFT = 4
static constant integer CENTER = 5
endstruct
struct Lightning extends array
private static location loc = Location(0.0, 0.0)
// there's a free list for each Lightning_Type
private static integer I = Lightning_Type.COUNT + 2
private static thistype array fl_heads // fl_heads[Lightning_Type.<type>] stores the head of that type
private thistype fl_next
// position update list
private static thistype puls = Lightning_Type.COUNT + 1 // sentinel node
private thistype pul_prev
private thistype pul_next
// color update list
private static thistype culs = Lightning_Type.COUNT + 2 // sentinel node
private thistype cul_prev
private thistype cul_next
private static timer ct = CreateTimer()
private static timer pt = CreateTimer()
private Lightning_Type type
private lightning lightning
//! textmacro LIGHTNING_LINK takes p
private Lightning_Link $p$type
private real $p$x //
private real $p$y // Lightning_Link.XYZ
private real $p$z //
private location $p$location // Lightning_Link.LOCATION
private unit $p$unit // Lightning_Link.UNIT
private item $p$item // Lightning_Link.ITEM
private destructable $p$destructable // Lightning_Link.DESTRUCTABLE
private rect $p$rect // Lightning_Link.RECT
private Lightning_Rect_Point $p$rect_point // Lightning_Link.RECT
private camerasetup $p$camera // Lightning_Link.CAMERA
private Lightning $p$lightning // Lightning_Link.LIGHTNING
private Lightning_End $p$lightning_end // Lightning_Link.LIGHTNING
real $p$z_offset
private boolean $p$ftt // follow through time
//! endtextmacro
//! runtextmacro LIGHTNING_LINK("src_")
//! runtextmacro LIGHTNING_LINK("dest_")
// animate color
private real a
private real r
private real g
private real b
private real sa
private real sr
private real sg
private real sb
private integer c_curr_step
private integer c_max_steps
static if DEBUG_MODE then
private boolean properly_configured
endif
private static method onInit takes nothing returns nothing
set puls.pul_prev = puls
set puls.pul_next = puls
set culs.cul_prev = culs
set culs.cul_next = culs
endmethod
static method init_default takes Lightning_Type lt returns thistype
local thistype this
if fl_heads[lt] != 0 then
set this = fl_heads[lt]
set fl_heads[lt] = fl_heads[lt].fl_next
else
set I = I + 1
if I > 8190 then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "|cffFF0000[Lightning] error: could not allocate a Lightning instance|r")
return 0
endif
set this = I
set this.type = lt
set this.lightning = AddLightningEx(lt.to_id(), false, src_x, src_y, src_z, dest_x, dest_y, dest_z)
endif
set this.fl_next = 0
set this.pul_prev = 0
set this.pul_next = 0
set this.cul_prev = 0
set this.cul_next = 0
//! textmacro LIGHTNING_LINK_DEFAULTS takes p
set this.$p$type = Lightning_Link.UNDEFINED
set this.$p$x = SAFE_HAVEN_X
set this.$p$y = SAFE_HAVEN_Y
set this.$p$z = SAFE_HAVEN_Z
set this.$p$location = null
set this.$p$unit = null
set this.$p$item = null
set this.$p$destructable = null
set this.$p$rect = null
set this.$p$camera = null
set this.$p$lightning = 0
set this.$p$z_offset = 0.0
set this.$p$ftt = false
//! endtextmacro
//! runtextmacro LIGHTNING_LINK_DEFAULTS("src_")
//! runtextmacro LIGHTNING_LINK_DEFAULTS("dest_")
static if DEBUG_MODE then
set this.properly_configured = false
endif
return this
endmethod
private static method pul_is_empty takes nothing returns boolean
return puls.pul_next == puls
endmethod
private static method pul_has_one_item takes nothing returns boolean
return not pul_is_empty() and puls.pul_next.pul_next == puls
endmethod
private method add_to_pul takes nothing returns nothing
set this.pul_prev = puls
set this.pul_next = puls.pul_next
set this.pul_prev.pul_next = this
set this.pul_next.pul_prev = this
endmethod
private method remove_from_pul takes nothing returns nothing
set this.pul_prev.pul_next = this.pul_next
set this.pul_next.pul_prev = this.pul_prev
set this.pul_prev = 0
set this.pul_next = 0
endmethod
private method is_in_pul takes nothing returns boolean
return this.pul_next != 0
endmethod
private static method cul_is_empty takes nothing returns boolean
return culs.cul_next == culs
endmethod
private static method cul_has_one_item takes nothing returns boolean
return not cul_is_empty() and culs.cul_next.cul_next == culs
endmethod
private method add_to_cul takes nothing returns nothing
set this.cul_prev = culs
set this.cul_next = culs.cul_next
set this.cul_prev.cul_next = this
set this.cul_next.cul_prev = this
endmethod
private method remove_from_cul takes nothing returns nothing
set this.cul_prev.cul_next = this.cul_next
set this.cul_next.cul_prev = this.cul_prev
set this.cul_prev = 0
set this.cul_next = 0
endmethod
private method is_in_cul takes nothing returns boolean
return this.cul_next != 0
endmethod
method destroy takes nothing returns nothing
static if DEBUG_MODE then
if this == 0 then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "|cffFF0000[Lightning] error: cannot destroy null Lightning instance|r")
return
endif
if this.fl_next != 0 then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "|cffFF0000[Lightning] error: cannot destroy Lightning(" + I2S(this) + ") instance more than once|r")
return
endif
endif
set this.src_x = SAFE_HAVEN_X
set this.src_y = SAFE_HAVEN_Y
set this.src_z = SAFE_HAVEN_Z
set this.src_z_offset = 0.0
set this.dest_x = SAFE_HAVEN_X
set this.dest_y = SAFE_HAVEN_Y
set this.dest_z = SAFE_HAVEN_Z
set this.dest_z_offset = 0.0
call this.move()
if this.is_in_pul() then
call this.remove_from_pul()
if pul_is_empty() then
call PauseTimer(pt)
endif
endif
if this.is_in_cul() then
call this.remove_from_cul()
if cul_is_empty() then
call PauseTimer(ct)
endif
endif
set this.fl_next = fl_heads[this.type]
set fl_heads[this.type] = this
endmethod
method move takes nothing returns nothing
static if DEBUG_MODE then
if not this.properly_configured then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "[Lightning] error: cannot call method move() for Lightning(" + I2S(this) + ") before it's configured")
return
endif
endif
call MoveLightningEx(this.lightning, false, this.src_x, this.src_y, this.src_z + this.src_z_offset, this.dest_x, this.dest_y, this.dest_z + this.dest_z_offset)
endmethod
private static method position_update takes nothing returns nothing
local thistype li
local Lightning_Link lt
local Lightning_Rect_Point rp
local Lightning_End other_end
set li = puls.pul_next
loop
exitwhen li == puls
if li.src_ftt then
set lt = li.src_type
if lt == Lightning_Link.LOCATION then
set li.src_x = GetLocationX(li.src_location)
set li.src_y = GetLocationY(li.src_location)
set li.src_z = GetLocationZ(li.src_location)
elseif lt == Lightning_Link.UNIT then
set li.src_x = GetUnitX(li.src_unit)
set li.src_y = GetUnitY(li.src_unit)
call MoveLocation(loc, li.src_x, li.src_y)
set li.src_z = GetLocationZ(loc) + GetUnitFlyHeight(li.src_unit)
elseif lt == Lightning_Link.ITEM then
set li.src_x = GetItemX(li.src_item)
set li.src_y = GetItemY(li.src_item)
call MoveLocation(loc, li.src_x, li.src_y)
set li.src_z = GetLocationZ(loc)
elseif lt == Lightning_Link.DESTRUCTABLE then
set li.src_x = GetDestructableX(li.src_destructable)
set li.src_y = GetDestructableY(li.src_destructable)
call MoveLocation(loc, li.src_x, li.src_y)
set li.src_z = GetLocationZ(loc)
elseif lt == Lightning_Link.RECT then
set rp = li.src_rect_point
if rp == Lightning_Rect_Point.TOP_LEFT then
set li.src_x = GetRectMinX(li.src_rect)
set li.src_y = GetRectMaxY(li.src_rect)
elseif rp == Lightning_Rect_Point.TOP_RIGHT then
set li.src_x = GetRectMaxX(li.src_rect)
set li.src_y = GetRectMaxY(li.src_rect)
elseif rp == Lightning_Rect_Point.BOTTOM_RIGHT then
set li.src_x = GetRectMaxX(li.src_rect)
set li.src_y = GetRectMinY(li.src_rect)
elseif rp == Lightning_Rect_Point.BOTTOM_LEFT then
set li.src_x = GetRectMinX(li.src_rect)
set li.src_y = GetRectMinY(li.src_rect)
else // if rp == Lightning_Rect_Point.CENTER then
set li.src_x = GetRectCenterX(li.src_rect)
set li.src_y = GetRectCenterY(li.src_rect)
endif
call MoveLocation(loc, li.src_x, li.src_y)
set li.src_z = GetLocationZ(loc)
elseif lt == Lightning_Link.CAMERA then
set li.src_x = CameraSetupGetDestPositionX(li.src_camera)
set li.src_y = CameraSetupGetDestPositionY(li.src_camera)
call MoveLocation(loc, li.src_x, li.src_y)
set li.src_z = CameraSetupGetField(li.src_camera, CAMERA_FIELD_ZOFFSET) + GetLocationZ(loc)
elseif lt == Lightning_Link.LIGHTNING then
if li.src_lightning_end == Lightning_End.SRC then
set li.src_x = li.src_lightning.src_x
set li.src_y = li.src_lightning.src_y
set li.src_z = li.src_lightning.src_z
else // if li.src_lighthing_end == Lightning_End.DEST then
set li.src_x = li.src_lightning.dest_x
set li.src_y = li.src_lightning.dest_y
set li.src_z = li.src_lightning.dest_z
endif
endif
endif
if li.dest_ftt then
set lt = li.dest_type
if lt == Lightning_Link.LOCATION then
set li.dest_x = GetLocationX(li.dest_location)
set li.dest_y = GetLocationY(li.dest_location)
set li.dest_z = GetLocationZ(li.dest_location)
elseif lt == Lightning_Link.UNIT then
set li.dest_x = GetUnitX(li.dest_unit)
set li.dest_y = GetUnitY(li.dest_unit)
call MoveLocation(loc, li.dest_x, li.dest_y)
set li.dest_z = GetLocationZ(loc) + GetUnitFlyHeight(li.dest_unit)
elseif lt == Lightning_Link.ITEM then
set li.dest_x = GetItemX(li.dest_item)
set li.dest_y = GetItemY(li.dest_item)
call MoveLocation(loc, li.dest_x, li.dest_y)
set li.dest_z = GetLocationZ(loc)
elseif lt == Lightning_Link.DESTRUCTABLE then
set li.dest_x = GetDestructableX(li.dest_destructable)
set li.dest_y = GetDestructableY(li.dest_destructable)
call MoveLocation(loc, li.dest_x, li.dest_y)
set li.dest_z = GetLocationZ(loc)
elseif lt == Lightning_Link.RECT then
set rp = li.dest_rect_point
if rp == Lightning_Rect_Point.TOP_LEFT then
set li.dest_x = GetRectMinX(li.dest_rect)
set li.dest_y = GetRectMaxY(li.dest_rect)
elseif rp == Lightning_Rect_Point.TOP_RIGHT then
set li.dest_x = GetRectMaxX(li.dest_rect)
set li.dest_y = GetRectMaxY(li.dest_rect)
elseif rp == Lightning_Rect_Point.BOTTOM_RIGHT then
set li.dest_x = GetRectMaxX(li.dest_rect)
set li.dest_y = GetRectMinY(li.dest_rect)
elseif rp == Lightning_Rect_Point.BOTTOM_LEFT then
set li.dest_x = GetRectMinX(li.dest_rect)
set li.dest_y = GetRectMinY(li.dest_rect)
else // if rp == Lightning_Rect_Point.CENTER then
set li.dest_x = GetRectCenterX(li.dest_rect)
set li.dest_y = GetRectCenterY(li.dest_rect)
endif
call MoveLocation(loc, li.dest_x, li.dest_y)
set li.dest_z = GetLocationZ(loc)
elseif lt == Lightning_Link.CAMERA then
set li.dest_x = CameraSetupGetDestPositionX(li.dest_camera)
set li.dest_y = CameraSetupGetDestPositionY(li.dest_camera)
call MoveLocation(loc, li.dest_x, li.dest_y)
set li.dest_z = CameraSetupGetField(li.src_camera, CAMERA_FIELD_ZOFFSET) + GetLocationZ(loc)
elseif lt == Lightning_Link.LIGHTNING then
if li.dest_lightning_end == Lightning_End.SRC then
set li.dest_x = li.dest_lightning.src_x
set li.dest_y = li.dest_lightning.src_y
set li.dest_z = li.dest_lightning.src_z
else // if li.dest_lighthing_end == Lightning_End.DEST then
set li.dest_x = li.dest_lightning.dest_x
set li.dest_y = li.dest_lightning.dest_y
set li.dest_z = li.dest_lightning.dest_z
endif
endif
endif
call MoveLightningEx(li.lightning, false, li.src_x, li.src_y, li.src_z + li.src_z_offset, li.dest_x, li.dest_y, li.dest_z + li.dest_z_offset)
set li = li.pul_next
endloop
endmethod
static method begin_configure takes Lightning_Type lightning_type returns thistype
return init_default(lightning_type)
endmethod
method end_configure takes nothing returns nothing
static if DEBUG_MODE then
set this.properly_configured = true
if this.src_type == Lightning_Link.UNDEFINED then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "[Lightning] error: Lightning(" + I2S(this) + ")'s SRC end has not been configured")
set this.properly_configured = false
endif
if this.dest_type == Lightning_Link.UNDEFINED then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "[Lightning] error: Lightning(" + I2S(this) + ")'s DEST end has not been configured")
set this.properly_configured = false
endif
endif
endmethod
method change_type takes Lightning_Type new_type returns thistype
local thistype result
static if DEBUG_MODE then
if not this.properly_configured then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "[Lightning] error: cannot call method change_type(...) for Lightning(" + I2S(this) + ") before it's configured")
return 0
endif
endif
if this.type == new_type then
return this
endif
set result = thistype.init_default(new_type)
//! textmacro LIGHTNING_LINK_COPY takes p
set result.$p$type = this.$p$type
set result.$p$x = this.$p$x
set result.$p$y = this.$p$y
set result.$p$z = this.$p$z
set result.$p$location = this.$p$location
set result.$p$unit = this.$p$unit
set result.$p$item = this.$p$item
set result.$p$destructable = this.$p$destructable
set result.$p$rect = this.$p$rect
set result.$p$rect_point = this.$p$rect_point
set result.$p$camera = this.$p$camera
set result.$p$lightning = this.$p$lightning
set result.$p$lightning_end = this.$p$lightning_end
set result.$p$z_offset = this.$p$z_offset
set result.$p$ftt = this.$p$ftt
//! endtextmacro
//! runtextmacro LIGHTNING_LINK_COPY("src_")
//! runtextmacro LIGHTNING_LINK_COPY("dest_")
set result.a = this.a
set result.r = this.r
set result.g = this.g
set result.b = this.b
set result.sa = this.sa
set result.sr = this.sr
set result.sg = this.sg
set result.sb = this.sb
set result.c_curr_step = this.c_curr_step
set result.c_max_steps = this.c_max_steps
static if DEBUG_MODE then
set result.properly_configured = this.properly_configured
endif
if this.is_in_pul() then
call result.add_to_pul()
endif
if this.is_in_cul() then
call result.add_to_cul()
endif
call this.destroy()
call result.move()
return result
endmethod
// must be called after end_configure
method follow_through_time takes Lightning_End end, boolean flag returns nothing
static if DEBUG_MODE then
if not this.properly_configured then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "[Lightning] error: cannot call method follow_through_time(...) for Lightning(" + I2S(this) + ") before it's configured")
return
endif
endif
if this.src_type == Lightning_Link.XYZ and this.dest_type == Lightning_Link.XYZ then
return
endif
if end == Lightning_End.SRC then
set this.src_ftt = flag
else // if end == Lightning_End.DEST then
set this.dest_ftt = flag
endif
if not this.is_in_pul() and flag then
call this.add_to_pul()
if pul_has_one_item() then
call TimerStart(pt, PDT, true, function thistype.position_update)
endif
elseif this.is_in_pul() and not this.src_ftt and not this.dest_ftt then
call this.remove_from_pul()
if pul_is_empty() then
call PauseTimer(pt)
endif
endif
endmethod
method set_end_xyz takes Lightning_End end, real x, real y, real z returns nothing
if end == Lightning_End.SRC then
set this.src_type = Lightning_Link.XYZ
set this.src_x = x
set this.src_y = y
set this.src_z = z
else // if end == Lightning_End.DEST then
set this.dest_type = Lightning_Link.XYZ
set this.dest_x = x
set this.dest_y = y
set this.dest_z = z
endif
endmethod
method set_end_location takes Lightning_End end, location l returns nothing
if end == Lightning_End.SRC then
set this.src_type = Lightning_Link.LOCATION
set this.src_location = l
set this.src_x = GetLocationX(l)
set this.src_y = GetLocationX(l)
set this.src_z = GetLocationZ(l)
else // if end == Lightning_End.DEST then
set this.dest_type = Lightning_Link.LOCATION
set this.dest_location = l
set this.dest_x = GetLocationX(l)
set this.dest_y = GetLocationX(l)
set this.dest_z = GetLocationZ(l)
endif
endmethod
method set_end_unit takes Lightning_End end, unit u returns nothing
if end == Lightning_End.SRC then
set this.src_type = Lightning_Link.UNIT
set this.src_unit = u
set this.src_x = GetUnitX(u)
set this.src_y = GetUnitY(u)
call MoveLocation(loc, this.src_x, this.src_y)
set this.src_z = GetLocationZ(loc) + GetUnitFlyHeight(u)
else // if end == Lightning_End.DEST then
set this.dest_type = Lightning_Link.UNIT
set this.dest_unit = u
set this.dest_x = GetUnitX(u)
set this.dest_y = GetUnitY(u)
call MoveLocation(loc, this.dest_x, this.dest_y)
set this.dest_z = GetLocationZ(loc) + GetUnitFlyHeight(u)
endif
endmethod
method set_end_item takes Lightning_End end, item it returns nothing
if end == Lightning_End.SRC then
set this.src_type = Lightning_Link.ITEM
set this.src_item = it
set this.src_x = GetItemX(it)
set this.src_y = GetItemY(it)
call MoveLocation(loc, this.src_x, this.src_y)
set this.src_z = GetLocationZ(loc)
else // if end == Lightning_End.DEST then
set this.dest_type = Lightning_Link.ITEM
set this.dest_item = it
set this.dest_x = GetItemX(it)
set this.dest_y = GetItemY(it)
call MoveLocation(loc, this.dest_x, this.dest_y)
set this.dest_z = GetLocationZ(loc)
endif
endmethod
method set_end_destructable takes Lightning_End end, destructable d returns nothing
if end == Lightning_End.SRC then
set this.src_type = Lightning_Link.DESTRUCTABLE
set this.src_destructable = d
set this.src_x = GetDestructableX(d)
set this.src_y = GetDestructableY(d)
call MoveLocation(loc, this.src_x, this.src_y)
set this.src_z = GetLocationZ(loc)
else // if end == Lightning_End.DEST then
set this.dest_type = Lightning_Link.DESTRUCTABLE
set this.dest_destructable = d
set this.dest_x = GetDestructableX(d)
set this.dest_y = GetDestructableY(d)
call MoveLocation(loc, this.dest_x, this.dest_y)
set this.dest_z = GetLocationZ(loc)
endif
endmethod
method set_end_rect takes Lightning_End end, rect r, Lightning_Rect_Point rp returns nothing
if end == Lightning_End.SRC then
set this.src_type = Lightning_Link.RECT
set this.src_rect = r
set this.src_rect_point = rp
if rp == Lightning_Rect_Point.TOP_LEFT then
set this.src_x = GetRectMinX(r)
set this.src_y = GetRectMaxY(r)
elseif rp == Lightning_Rect_Point.TOP_RIGHT then
set this.src_x = GetRectMaxX(r)
set this.src_y = GetRectMaxY(r)
elseif rp == Lightning_Rect_Point.BOTTOM_RIGHT then
set this.src_x = GetRectMaxX(r)
set this.src_y = GetRectMinY(r)
elseif rp == Lightning_Rect_Point.BOTTOM_LEFT then
set this.src_x = GetRectMinX(r)
set this.src_y = GetRectMinY(r)
else // if rp == Lightning_Rect_Point.CENTER then
set this.src_x = GetRectCenterX(r)
set this.src_y = GetRectCenterY(r)
endif
call MoveLocation(loc, this.src_x, this.src_y)
set this.src_z = GetLocationZ(loc)
else // if end == Lightning_End.DEST then
set this.dest_type = Lightning_Link.RECT
set this.dest_rect = r
set this.dest_rect_point = rp
if rp == Lightning_Rect_Point.TOP_LEFT then
set this.dest_x = GetRectMinX(r)
set this.dest_y = GetRectMaxY(r)
elseif rp == Lightning_Rect_Point.TOP_RIGHT then
set this.dest_x = GetRectMaxX(r)
set this.dest_y = GetRectMaxY(r)
elseif rp == Lightning_Rect_Point.BOTTOM_RIGHT then
set this.dest_x = GetRectMaxX(r)
set this.dest_y = GetRectMinY(r)
elseif rp == Lightning_Rect_Point.BOTTOM_LEFT then
set this.dest_x = GetRectMinX(r)
set this.dest_y = GetRectMinY(r)
else // if rp == Lightning_Rect_Point.CENTER then
set this.dest_x = GetRectCenterX(r)
set this.dest_y = GetRectCenterY(r)
endif
call MoveLocation(loc, this.dest_x, this.dest_y)
set this.dest_z = GetLocationZ(loc)
endif
endmethod
method set_end_camera takes Lightning_End end, camerasetup camera returns nothing
if end == Lightning_End.SRC then
set this.src_type = Lightning_Link.CAMERA
set this.src_camera = camera
set this.src_x = CameraSetupGetDestPositionX(camera)
set this.src_y = CameraSetupGetDestPositionY(camera)
call MoveLocation(loc, this.src_x, this.src_y)
set this.src_z = CameraSetupGetField(camera, CAMERA_FIELD_ZOFFSET) + GetLocationZ(loc)
else // if end == Lightning_End.DEST then
set this.dest_type = Lightning_Link.CAMERA
set this.dest_camera = camera
set this.dest_x = CameraSetupGetDestPositionX(camera)
set this.dest_y = CameraSetupGetDestPositionY(camera)
call MoveLocation(loc, this.dest_x, this.dest_y)
set this.dest_z = CameraSetupGetField(camera, CAMERA_FIELD_ZOFFSET) + GetLocationZ(loc)
endif
endmethod
method set_end_lightning takes Lightning_End own_end, Lightning other, Lightning_End other_end returns nothing
if own_end == Lightning_End.SRC then
set this.src_type = Lightning_Link.LIGHTNING
set this.src_lightning = other
set this.src_lightning_end = other_end
if other_end == Lightning_End.SRC then
set this.src_x = other.src_x
set this.src_y = other.src_y
set this.src_z = other.src_z
else // if other_end == Lightning_End.DEST then
set this.src_x = other.dest_x
set this.src_y = other.dest_y
set this.src_z = other.dest_z
endif
else // if own_end == Lightning_End.DEST then
set this.dest_type = Lightning_Link.LIGHTNING
set this.dest_lightning = other
set this.dest_lightning_end = other_end
if other_end == Lightning_End.SRC then
set this.dest_x = other.src_x
set this.dest_y = other.src_y
set this.dest_z = other.src_z
else // if other_end == Lightning_End.DEST then
set this.dest_x = other.dest_x
set this.dest_y = other.dest_y
set this.dest_z = other.dest_z
endif
endif
endmethod
private static integer alpha = 0
private static integer red = 0
private static integer green = 0
private static integer blue = 0
private static method get_argb takes integer color returns nothing
local boolean is_neg = color < 0
local integer t
if is_neg then
set color = color + 0x80000000
endif
set t = color / 0x100
set blue = color - t * 0x100
set color = t
set t = color / 0x100
set green = color - t * 0x100
set color = t
set t = color / 0x100
set red = color - t * 0x100
set color = t
set t = color / 0x100
set alpha = color - t * 0x100
// set color = t
if is_neg then
set alpha = alpha + 0x80
endif
endmethod
method set_color takes integer color returns nothing
static if DEBUG_MODE then
if not this.properly_configured then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "[Lightning] error: cannot call method set_color(...) for Lightning(" + I2S(this) + ") before it's configured")
return
endif
endif
call get_argb(color)
call SetLightningColor(this.lightning, red / 255.0, green / 255.0, blue / 255.0, alpha / 255.0)
endmethod
private static method animate_step takes nothing returns nothing
local thistype li
local thistype li_next
set li = culs.cul_next
loop
exitwhen li == culs
set li_next = li.cul_next
call SetLightningColor(li.lightning, li.r, li.g, li.b, li.a)
set li.c_curr_step = li.c_curr_step + 1
if li.c_curr_step > li.c_max_steps then
call li.remove_from_cul()
if cul_is_empty() then
call PauseTimer(ct)
endif
else
set li.a = li.a + li.sa
set li.r = li.r + li.sr
set li.g = li.g + li.sg
set li.b = li.b + li.sb
endif
set li = li_next
endloop
endmethod
method animate takes integer start_color, integer end_color, real dur returns nothing
static if DEBUG_MODE then
if not this.properly_configured then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "[Lightning] error: cannot call method animate(...) for Lightning(" + I2S(this) + ") before it's configured")
return
endif
endif
call get_argb(start_color)
set this.a = alpha / 255.0
set this.r = red / 255.0
set this.g = green / 255.0
set this.b = blue / 255.0
call get_argb(end_color)
if dur < CDT then
call SetLightningColor(this.lightning, red / 255.0, green / 255.0, blue / 255.0, alpha / 255.0)
return
endif
set this.c_max_steps = R2I(1.0 / CDT * dur)
set this.c_curr_step = 0
set this.sa = (alpha / 255.0 - this.a) / c_max_steps
set this.sr = (red / 255.0 - this.r) / c_max_steps
set this.sg = (green / 255.0 - this.g) / c_max_steps
set this.sb = (blue / 255.0 - this.b) / c_max_steps
if not this.is_in_cul() then
call this.add_to_cul()
if cul_has_one_item() then
call TimerStart(ct, CDT, true, function thistype.animate_step)
endif
endif
endmethod
private static method timed_destroy takes nothing returns nothing
call Lightning(Timer.get_expired_data()).destroy()
endmethod
method timed takes real dur returns nothing
static if DEBUG_MODE then
if not this.properly_configured then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "[Lightning] error: cannot call method timed(...) for Lightning(" + I2S(this) + ") before it's configured")
return
endif
endif
call Timer.start(this, dur, function thistype.timed_destroy)
endmethod
static if DEBUG_MODE then
method debug takes nothing returns nothing
// call BJDebugMsg("Lightning { id: " + I2S(this) + ", type: " + this.type.to_str()) + ", src_x: " + R2S(this.src_x) + ", src_y: " + R2S(this.src_y) + ", src_z: " + R2S(this.src_z) + I2S(this) + ", dest_x: " + R2S(this.dest_x) + ", dest_y: " + R2S(this.dest_y) + ", dest_z: " + R2S(this.dest_z) + " }")
// call MoveLocation(loc, this.dest_x, this.dest_y)
// call BJDebugMsg("dest location z: " + R2S(GetLocationZ(loc)))
// call BJDebugMsg("a: " + R2S(this.a))
// call BJDebugMsg("r: " + R2S(this.r))
// call BJDebugMsg("g: " + R2S(this.g))
// call BJDebugMsg("b: " + R2S(this.b))
endmethod
endif
endstruct
endlibrary