scope BurningOrbit initializer init
//*************************************************************************************************************//
// Shocking Fence v0.01 //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// Vector lib by //
// Heights by cedi //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
private keyword Sub
private keyword Main
globals
//ID of the spell
private constant integer SPELL_ID = 'A000'
//ID of your dummy
private constant integer DUMMY_ID = 'h000'
//Interval of the moves
private constant real TIMER_INTERVAL = 0.035
//Main
//Height between each fence
private constant real MAIN_HEIGHT = 20.00
//MS of the fence when it is in the air ( in wc3 units )
private constant real MAIN_SPEED = 500.00
//Distance needed of the fence to the unit when the fence flies.
private constant real MAIN_COL = 10.00
//Angle of the bow when the fence flies. Like oe value.
private constant real MAIN_FLY_HEIGHT = 0.45
//Time needed between each time damage
private constant real MAIN_DAMAGE_INT = 2.00
//Percent of the full damage each time the fence deals damage.
private constant real MAIN_DMG_PERCENT = 0.10 //% pro interval
//SFX when the fence damages a unit.
private constant string MAIN_DMG_SFX = "Abilities\\Spells\\Orc\\FeralSpirit\\feralspiritdone.mdl"
//Sub
//Color rgb.
private constant integer SUB_COLOR_RED = 255
private constant integer SUB_COLOR_GREEN = 255
private constant integer SUB_COLOR_BLUE = 255
private constant integer SUB_COLOR_ALPHA = 255
//Count of the corners
private constant integer SUB_MAX = 6
//Distance to the unit ( of the corners )
private constant real SUB_DISTANCE = 75.00
//Amount of grad the corners turn each second.
private constant real SUB_TURN_SPEED = 180.00
//Size of the corner units
private constant real SUB_SIZE = 1.00
//Model of the corners
private constant string SUB_MODEL = "Abilities\\Weapons\\VengeanceMissile\\VengeanceMissile.mdl"
//Lightning
//Color of the lightning in rgb. ( these things are very strange, looks like they're in percent. )
private constant real LIGHT_COLOR_RED = 1
private constant real LIGHT_COLOR_GREEN = 1
private constant real LIGHT_COLOR_BLUE = 1
private constant real LIGHT_COLOR_ALPHA = 1
//If of the lightning.
private constant string LIGHT_ID = "AFOD"
//System
private vector AXIS
private hashtable HASH = InitHashtable()
private trigger DAMAGE_TRIG = CreateTrigger()
private trigger SPELL_TRIG = CreateTrigger()
private real TEMPREAL
private unit TEMPUNIT
private Main TEMPMAIN
endglobals
private function DAMAGE takes integer level returns real
return 100.00 + 20.00 * level
endfunction
private function SHIELD takes integer level returns real
return 100.00 + 20.00 * level
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private function AngleBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
private function DistanceBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
private function AngleBetweenUnits takes unit u, unit u2 returns real
return bj_RADTODEG * Atan2(GetUnitY( u2 ) - GetUnitY( u ), GetUnitX( u2 ) - GetUnitX( u ))
endfunction
private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
private function Heal takes nothing returns nothing
call DestroyTimer( GetExpiredTimer() )
call SetWidgetLife( TEMPUNIT, GetWidgetLife( TEMPUNIT ) + TEMPREAL )
endfunction
private function ParabolaZ2 takes real y0, real y1, real h, real d, real x returns real
local real A = (2*(y0+y1)-4*h)/(d*d)
local real B = (y1-y0-A*d*d)/d
return A*x*x + B*x + y0
endfunction
private function OuterControl takes nothing returns nothing
set TEMPMAIN = GetTimerData( GetExpiredTimer() )
call TEMPMAIN.control()
endfunction
private struct Sub
unit u
lightning l
Main root
vector dist
effect model
method onDestroy takes nothing returns nothing
call DestroyEffect( .model )
set .model = null
call KillUnit( .u )
set .u = null
call DestroyLightning( .l )
set .l = null
call .dist.destroy()
endmethod
method turn takes nothing returns nothing
call .dist.rotate( AXIS, SUB_TURN_SPEED * TIMER_INTERVAL * bj_DEGTORAD )
call SetUnitX( .u, .root.posi.x + .dist.x )
call SetUnitY( .u, .root.posi.y + .dist.y )
if GetUnitZ( .root.target ) != GetUnitZ( .u ) then
call SetUnitZ( .u, .root.posi.z )
endif
endmethod
method setLightning takes integer i returns nothing
local real x = 0.00
local real y = 0.00
local real z = .root.posi.z
local real tx = .dist.x + .root.posi.x
local real ty = .dist.y + .root.posi.y
if i >= SUB_MAX - 1 then
set x = .root.sub[0].dist.x + .root.posi.x
set y = .root.sub[0].dist.y + .root.posi.y
else
set x = .root.sub[i + 1].dist.x + .root.posi.x
set y = .root.sub[i + 1].dist.y + .root.posi.y
endif
call MoveLightningEx( .l, false, tx, ty, z, x, y, z )
endmethod
static method create takes Main root, integer count returns thistype
local thistype this = thistype.allocate()
local real angle = 360.00 / SUB_MAX * count * bj_DEGTORAD
set .root = root
set .dist = vector.create( Cos( angle ) * SUB_DISTANCE, Sin( angle ) * SUB_DISTANCE, 0.00 )
set .u = CreateUnit( GetOwningPlayer( .root.caster ), DUMMY_ID, .root.posi.x + .dist.x, .root.posi.y + .dist.x, 0.00 )
set .model = AddSpecialEffectTarget( SUB_MODEL, .u, "origin" )
call SetUnitVertexColor( .u, SUB_COLOR_RED, SUB_COLOR_GREEN, SUB_COLOR_BLUE, SUB_COLOR_ALPHA )
call SetUnitScale( .u, SUB_SIZE, SUB_SIZE, SUB_SIZE )
set .l = AddLightningEx( LIGHT_ID, false, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00 )
call SetLightningColor( .l, LIGHT_COLOR_RED, LIGHT_COLOR_GREEN, LIGHT_COLOR_BLUE, LIGHT_COLOR_ALPHA )
return this
endmethod
endstruct
private struct Main
unit target = null
unit caster = null
Sub array sub[SUB_MAX]
vector posi = 0
vector start = 0
real shield = 0.00
real damage = 0.00
real interval = MAIN_DAMAGE_INT
integer level = 1
integer number = 1
boolean jumping = false
boolean friend = false
timer t = null
method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= SUB_MAX
call .sub[i].destroy()
set i = i + 1
endloop
call SaveInteger( HASH, GetHandleId( .target ), 0, .number - 1 )
call SaveInteger( HASH, GetHandleId( .target ), .number, 0 )
set .target = null
set .caster = null
call .posi.destroy()
call .start.destroy()
call ReleaseTimer( .t )
set .t = null
endmethod
method control takes nothing returns nothing
local integer i = 0
local real z
local real x
local real y
local real dist
local real angle
set .interval = .interval - TIMER_INTERVAL
if GetWidgetLife( .target ) <= 0.405 then
call .destroy()
return
endif
//Main move
if .jumping then
if DistanceBetweenCoordinates( .posi.x, GetUnitX( .target ), .posi.y, GetUnitY( .target ) ) <= MAIN_COL then
if not HaveSavedInteger( HASH, GetHandleId( .target ), 0 ) then
set .number = 1
call SaveInteger( HASH, GetHandleId( .target ), 0, 1 )
else
set .number = LoadInteger( HASH, GetHandleId( .target ), 0 ) + 1
call SaveInteger( HASH, GetHandleId( .target ), 0, .number )
endif
call SaveInteger( HASH, GetHandleId( .target ), .number, this )
call .start.destroy()
set .jumping = false
set .posi.x = GetUnitX( .target )
set .posi.y = GetUnitY( .target )
set .posi.z = GetUnitZ( .target ) + MAIN_HEIGHT * .number
set .shield = SHIELD( .level )
set .damage = DAMAGE( .level )
else
set angle = AngleBetweenCoordinates( .posi.x, GetUnitX( .target ), .posi.y, GetUnitY( .target ) ) * bj_DEGTORAD
set dist = DistanceBetweenCoordinates( .start.x, GetUnitX( .target ), .start.y, GetUnitY( .target ) )
set x = .posi.x + Cos( angle ) * MAIN_SPEED * TIMER_INTERVAL
set y = .posi.y + Sin( angle ) * MAIN_SPEED * TIMER_INTERVAL
set z = ParabolaZ2( .start.z, GetUnitZ( .target ), dist * MAIN_FLY_HEIGHT, dist, DistanceBetweenCoordinates( .start.x, x, .start.y, y ) )
set .posi.x = x
set .posi.y = y
set .posi.z = z
endif
else
set .posi.x = GetUnitX( .target )
set .posi.y = GetUnitY( .target )
set .posi.z = GetUnitZ( .target ) + MAIN_HEIGHT * .number
endif
//Turn
loop
exitwhen i >= SUB_MAX
call .sub[i].turn()
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= SUB_MAX
call .sub[i].setLightning( i )
set i = i + 1
endloop
endmethod
method TookDamage takes unit damager, real damage returns nothing
local real r
local timer t
if .friend and not .jumping then
if damage >= .shield then
set damage = damage - .shield
call .destroy()
else
set .shield = .shield - damage
endif
set r = GetUnitState( .target, UNIT_STATE_MAX_LIFE ) - GetWidgetLife( .target )
if damage > r then
call SetWidgetLife( .target, GetWidgetLife( .target ) + r )
set TEMPREAL = damage - r
set TEMPUNIT = .target
set t = CreateTimer()
call TimerStart( t, 0.00, false, function Heal )
set t = null
else
call SetWidgetLife( .target, GetWidgetLife( .target ) + damage )
endif
else
if .interval <= 0.00 then
set .interval = MAIN_DAMAGE_INT
set .damage = .damage - DAMAGE( .level ) * MAIN_DMG_PERCENT
call DisableTrigger( DAMAGE_TRIG )
call UnitDamageTarget( .caster, .target, DAMAGE( .level ) * MAIN_DMG_PERCENT, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call EnableTrigger( DAMAGE_TRIG )
call DestroyEffect( AddSpecialEffectTarget( MAIN_DMG_SFX, .target, "chest" ) )
if .damage <= 0.00 then
call .destroy()
endif
endif
endif
endmethod
method NewTarget takes unit target returns nothing
call SaveInteger( HASH, GetHandleId( .target ), 0, .number - 1 )
call SaveInteger( HASH, GetHandleId( .target ), .number, 0 )
set .target = target
set .start = vector.create( .posi.x, .posi.y, .posi.z )
set .jumping = true
if IsUnitEnemy( target, GetOwningPlayer( .caster ) ) then
set .friend = false
else
set .friend = true
endif
endmethod
static method create takes unit caster, unit target returns thistype
local thistype this = thistype.allocate()
local integer i = 0
set .caster = caster
set .target = target
if not HaveSavedInteger( HASH, GetHandleId( target ), 0 ) then
set .number = 1
call SaveInteger( HASH, GetHandleId( target ), 0, 1 )
else
set .number = LoadInteger( HASH, GetHandleId( target ), 0 ) + 1
call SaveInteger( HASH, GetHandleId( target ), 0, .number )
endif
call SaveInteger( HASH, GetHandleId( target ), .number, this )
set .posi = vector.create( GetUnitX( target ), GetUnitY( target ), GetUnitZ( target ) + MAIN_HEIGHT * .number )
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .shield = SHIELD( .level )
set .damage = DAMAGE( .level )
loop
exitwhen i >= SUB_MAX
set .sub[i] = Sub.create( this, i )
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= SUB_MAX
call .sub[i].setLightning( i )
set i = i + 1
endloop
if IsUnitEnemy( target, GetOwningPlayer( caster ) ) then
set .friend = false
else
set .friend = true
endif
set .t = NewTimer()
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function OuterControl )
return this
endmethod
endstruct
private function UnderFence takes nothing returns boolean
if HaveSavedInteger( HASH, GetHandleId( GetSpellTargetUnit() ), 0 ) then
set TEMPMAIN = LoadInteger( HASH, GetHandleId( GetSpellTargetUnit() ), LoadInteger( HASH, GetHandleId( GetSpellTargetUnit() ), 0 ) )
call TEMPMAIN.NewTarget( GetTriggerUnit() )
endif
return false
endfunction
private function TakesDamage takes nothing returns boolean
if HaveSavedInteger( HASH, GetHandleId( GetTriggerUnit() ), 0 ) then
set TEMPMAIN = LoadInteger( HASH, GetHandleId( GetTriggerUnit() ), LoadInteger( HASH, GetHandleId( GetTriggerUnit() ), 0 ) )
call TEMPMAIN.TookDamage( GetEventDamageSource(), GetEventDamage() )
endif
return false
endfunction
private function IsSpell takes nothing returns nothing
if GetSpellAbilityId() == SPELL_ID then
call DisableTrigger( SPELL_TRIG )
call Main.create( GetTriggerUnit(), GetSpellTargetUnit() )
call PolledWait( 0.4 )
call EnableTrigger( SPELL_TRIG )
endif
endfunction
private function AddToTakesDamage takes nothing returns nothing
call TriggerRegisterUnitEvent( DAMAGE_TRIG, GetTriggerUnit(), EVENT_UNIT_DAMAGED )
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
local trigger t3 = CreateTrigger()
local group g = CreateGroup()
local unit u
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddAction( t, function IsSpell )
call TriggerRegisterAnyUnitEventBJ( SPELL_TRIG, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( SPELL_TRIG, Condition( function UnderFence ) )
call TriggerRegisterEnterRectSimple( t3, GetWorldBounds() )
call TriggerAddAction( t3, function AddToTakesDamage )
call TriggerAddCondition( DAMAGE_TRIG, Condition( function TakesDamage ) )
call GroupEnumUnitsInRange( g, 0.00, 0.00, 9999999.00, null )
loop
set u = FirstOfGroup( g )
exitwhen u == null
call TriggerRegisterUnitEvent( DAMAGE_TRIG, u, EVENT_UNIT_DAMAGED )
call GroupRemoveUnit( g, u )
set u = null
endloop
call DestroyGroup( g )
set g = null
set AXIS = vector.create( 0.00, 0.00, 1.00 )
set t = null
endfunction
endscope