Moderator
M
Moderator
08:21, 14th Apr 2010
TriggerHappy:
Coding was fine, but it was very similar to your other spell.
TriggerHappy:
Coding was fine, but it was very similar to your other spell.
scope ShadowShot initializer init
//*************************************************************************************************************//
// Shadow Shot v0.02 //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// IsTerrainWalkable by Antiarf //
// //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
private keyword Main
private keyword Sub
private keyword Arrow
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
//Shooters
//Color in rgb
private constant integer S_COLOR_RED = 255
private constant integer S_COLOR_GREEN = 255
private constant integer S_COLOR_BLUE = 255
//Alpha color reached befor shot.
private constant integer S_COLOR_ALPHA = 125
//Time the units need to appear.
private constant real SHOW_TIME = 1.00
//Time the units need to disappear.
private constant real HIDE_TIME = 1.00
//Time of the attack animation.
private constant real ANIMATION_TIME = 0.70
//Size of the units
private constant real SHOOTER_SIZE = 1.00
//Z-start of the missiles
private constant real SHOOTER_MISSILE_Z = 60.00
//Place a unit needs
private constant real SHOOTER_COL = 100.00
//Max angle the units can have
private constant real SHOOTER_ANGLE = 45.00
//Animation string
private constant string ANIMATION = "attack"
//Missile
//Color in rgb
private constant integer M_COLOR_RED = 255
private constant integer M_COLOR_GREEN = 255
private constant integer M_COLOR_BLUE = 255
private constant integer M_COLOR_ALPHA = 125
//Pick units in each
private constant integer PICK_EACH_X_TIMES = 3
//Speed of the arrows in wc3 units
private constant real SPEED = 600.00
//Size of the missile
private constant real MISSILE_SIZE = 1.00
//Model of the missile
private constant string MODEL = "Abilities\\Weapons\\Arrow\\ArrowMissile.mdl"
//SFX on damage
private constant string DAMAGE_SFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl"
//Additionall model
private constant string ADD_MODEL = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
//Should the missile disappear on collision with doodads cliff ...
private constant boolean IS_COLLISION = false
//System
private Main TEMPMAIN
private Sub TEMPSUB
private Arrow TEMPARROW
private group TEMPGROUP = CreateGroup()
private hashtable HASH = InitHashtable()
endglobals
private function HIT_FUNC takes Arrow arrow, unit target returns nothing
//Do your uber crazy things, like knockback, dot, slow ...
endfunction
private function DAMAGE takes integer level returns real
return 100.00 + 50 * level
endfunction
private function AOE takes integer level returns real
return 55.00 + 5 * 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 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 OuterControl takes nothing returns nothing
set TEMPMAIN = GetTimerData( GetExpiredTimer() )
call TEMPMAIN.control()
endfunction
private function A_OuterControl takes nothing returns nothing
set TEMPARROW = GetTimerData( GetExpiredTimer() )
call TEMPARROW.control()
endfunction
private struct Arrow
unit u = null
unit caster = null
effect model = null
effect sfx = null
group g = null
real range = 0.00
real dist = 0.00
real vx = 0.00
real vy = 0.00
real alpha = M_COLOR_ALPHA
real alphalose = 0.00
integer level = 1
integer times = 0
timer t = null
boolean vanish = false
method onDestroy takes nothing returns nothing
call ReleaseTimer( .t )
set .t = null
call DestroyEffect( .model )
call DestroyEffect( .sfx )
set .model = null
set .sfx = null
call KillUnit( .u )
set .u = null
call GroupClear( .g )
call DestroyGroup( .g )
set .g = null
endmethod
method dealDamage takes unit u returns nothing
call DestroyEffect( AddSpecialEffectTarget( DAMAGE_SFX, u, "chest" ) )
if .vanish then
call UnitDamageTarget( .caster, u, DAMAGE( .level ) * .alpha / M_COLOR_ALPHA, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
else
call UnitDamageTarget( .caster, u, DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
endif
call HIT_FUNC( this, u )
endmethod
method control takes nothing returns nothing
local real x = GetUnitX( .u ) + .vx
local real y = GetUnitY( .u ) + .vy
local unit u
if GetWidgetLife( .u ) <= 0.405 then
call .destroy()
endif
if not .vanish then
set .dist = .dist - SPEED * TIMER_INTERVAL
if .dist <= 0.00 then
set .vanish = true
endif
endif
if .vanish then
set .alpha = .alpha - .alphalose
call SetUnitVertexColor( .u, M_COLOR_RED, M_COLOR_GREEN, M_COLOR_GREEN, R2I( .alpha + 0.5 ) )
endif
set .range = .range - SPEED * TIMER_INTERVAL
call SetUnitX( .u, x )
call SetUnitY( .u, y )
if IS_COLLISION then
if not IsTerrainWalkable( x, y ) then
call .destroy()
endif
endif
set .times = .times + 1
if .times >= PICK_EACH_X_TIMES then
set .times = 0
call GroupEnumUnitsInRange( TEMPGROUP, x, y, AOE( .level ), Condition( function IsAliveAndUnitAndNotMagicImmune ) )
loop
set u = FirstOfGroup( TEMPGROUP )
exitwhen u == null
if IsUnitEnemy( u, GetOwningPlayer( .caster ) ) then
if not IsUnitInGroup( u, .g ) then
call .dealDamage( u )
call GroupAddUnit( .g, u )
endif
endif
call GroupRemoveUnit( TEMPGROUP, u )
set u = null
endloop
endif
if .range <= 0.00 then
call .destroy()
endif
endmethod
static method create takes Main root, real x, real y, real angle returns thistype
local thistype this = thistype.allocate()
set .caster = root.caster
set .g = CreateGroup()
set .range = root.distance * 2.00
set .level = root.level
set .dist = root.distance
set .vx = Cos( angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set .vy = Sin( angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set .u = CreateUnit( GetOwningPlayer( .caster ), DUMMY_ID, x, y, angle )
set .model = AddSpecialEffectTarget( MODEL, .u, "origin" )
set .sfx = AddSpecialEffectTarget( ADD_MODEL, .u, "origin" )
set .alphalose = M_COLOR_ALPHA * TIMER_INTERVAL / ( .dist / ( SPEED * TIMER_INTERVAL ) )
call SetUnitFlyHeight( .u, SHOOTER_MISSILE_Z, 0 )
call SetUnitScale( .u, MISSILE_SIZE, MISSILE_SIZE, MISSILE_SIZE )
call SetUnitVertexColor( .u, S_COLOR_RED, S_COLOR_GREEN, S_COLOR_BLUE, S_COLOR_ALPHA )
set .t = NewTimer()
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function A_OuterControl )
return this
endmethod
endstruct
private struct Sub
unit u = null
real angle = 0.00
Main root = 0
method onDestroy takes nothing returns nothing
call KillUnit( .u )
call RemoveUnit( .u )
set .u = null
endmethod
method shot takes nothing returns nothing
call Arrow.create( .root, GetUnitX( .u ), GetUnitY( .u ), .angle )
endmethod
method attack takes nothing returns nothing
call SetUnitAnimation( .u, ANIMATION )
endmethod
method adjustAlpha takes nothing returns nothing
call SetUnitVertexColor( .u, S_COLOR_RED, S_COLOR_GREEN, S_COLOR_BLUE, R2I( .root.alpha + 0.5 ) )
endmethod
static method create takes Main root, real angle returns thistype
local thistype this = thistype.allocate()
local real x = root.x + Cos( angle * bj_DEGTORAD ) * root.distance
local real y = root.y + Sin( angle * bj_DEGTORAD ) * root.distance
set .root = root
set .angle = angle + 180.00
set .u = CreateUnit( Player( 12 ), GetUnitTypeId( root.caster ), x, y, .angle )
call SetUnitColor( .u, GetPlayerColor( GetOwningPlayer( root.caster ) ) )
call SetUnitScale( .u, SHOOTER_SIZE, SHOOTER_SIZE, SHOOTER_SIZE )
call SetUnitVertexColor( .u, S_COLOR_RED, S_COLOR_GREEN, S_COLOR_BLUE, R2I( root.alpha ) )
call SetUnitPathing( .u, false )
call SetUnitX( .u, x )
call SetUnitY( .u, y )
call UnitAddAbility( .u, 'Aloc' )
call PauseUnit( .u, true )
return this
endmethod
endstruct
private struct Main
unit caster = null
integer shooter = 0
real alpha = 0
integer level = 1
real time = 0.00
real x = 0.00
real y = 0.00
real distance = 0.00
timer t = null
boolean show = true
boolean shot = false
boolean hide = false
method control takes nothing returns nothing
local real r
local integer i
//SHOW
if .show then
set r = S_COLOR_ALPHA * TIMER_INTERVAL / SHOW_TIME
set .alpha = .alpha + r
set .time = .time - TIMER_INTERVAL
set i = 0
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.adjustAlpha()
set i = i + 1
endloop
if .time <= 0.00 then
set .show = false
set .shot = true
set .time = ANIMATION_TIME
set i = 0
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.attack()
set i = i + 1
endloop
endif
return
endif
//ATTACK
if .shot then
set .time = .time - TIMER_INTERVAL
if .time <= 0.00 then
set i = 0
set .shot = false
set .hide = true
set .time = HIDE_TIME
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.shot()
set i = i + 1
endloop
endif
return
endif
//HIDE
if .hide then
set r = S_COLOR_ALPHA * TIMER_INTERVAL / SHOW_TIME
set .alpha = .alpha - r
set .time = .time - TIMER_INTERVAL
set i = 0
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.adjustAlpha()
set i = i + 1
endloop
if .time <= 0.00 then
call .destroy()
endif
endif
endmethod
method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.destroy()
set i = i + 1
endloop
call FlushChildHashtable( HASH, this )
set .caster = null
call ReleaseTimer( .t )
set .t = null
endmethod
static method create takes unit caster, real x, real y returns thistype
local thistype this = thistype.allocate()
local real distance = DistanceBetweenCoordinates( GetUnitX( caster ), x, GetUnitY( caster ), y )
local real bogen = 2 * bj_PI * distance * ( SHOOTER_ANGLE * 2.00 ) / 360.00
local integer count = R2I( bogen / SHOOTER_COL + 0.5 )
local real angle = AngleBetweenCoordinates( GetUnitX( caster ), x, GetUnitY( caster ), y )
local real r = 0.00
local integer i = 0
set bogen = SHOOTER_ANGLE * 2 / count
set .caster = caster
set .shooter = count
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .time = SHOW_TIME
set .alpha = 0
set .x = x
set .y = y
set .t = NewTimer()
set .distance = distance
call SetTimerData( .t, this )
set r = ( angle + 180.00 ) - SHOOTER_ANGLE
loop
exitwhen i > count
set TEMPSUB = Sub.create( this, r )
call SaveInteger( HASH, this, i, TEMPSUB )
set r = r + bogen
set i = i + 1
endloop
call TimerStart( .t, TIMER_INTERVAL, true, function OuterControl )
return this
endmethod
endstruct
private function IsSpell takes nothing returns nothing
if GetSpellAbilityId() == SPELL_ID then
call Main.create( GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY() )
endif
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddAction( t, function IsSpell )
set t = null
endfunction
endscope