Способность для обучения начинающих, но посложнее!
Возможны баги, но автор их не обнаружил :)
Возможны баги, но автор их не обнаружил :)
MUI - только для разных игроков.
Видео
Код
globals
hashtable HT = InitHashtable()
group Group = CreateGroup()
group FastGroup
player CasterOwner
unit Caster
unit Dummy
unit EnumUnit
timer Timer
timer FastTimer
integer TimerId
integer FastTimerId
integer CasterId
integer Tick
integer Alpha
real Time
real Angle
real FastAngle
real Distance
real Range
real Scale
real Charge
real CasterX
real CasterY
real CastX
real CastY
real StartX
real StartY
real NewX
real NewY
// Айди способностей и периодичность таймера
constant integer WaterDragon_SpellPreparationId = 'A000'
constant integer WaterDragon_SpellShotId = 'A001'
constant real WaterDragon_TimerPeriod = 0.03
constant real WaterDragon_PreparationTime = 3
// Айди даммиков
constant integer WaterDragon_DummyId = 'h000'
constant integer WaterDragon_PreparationDummyId = 'h001'
// Строки
constant string WaterDragon_MoveEffectPath = "war3mapImported\\AquaSpike.mdx"
constant string WaterDragon_OrderString = "wateryminion"
constant string WaterDragon_ChargeText = "|cFFBBEEFFWater Dragon Charge: "
constant string WaterDragon_TimeText = "|cFFBBEEFFTime Left For Cast: "
// Длительности
constant real WaterDragon_ChargeTextDuration = 5
constant real WaterDragon_TimeTextDuration = 5
// Ограничения и скорость убавления непрозрачности
constant integer WaterDragon_TimeLeftForCast = 3
constant integer WaterDragon_AlphaRemovingSpeed = 32
constant integer WaterDragon_EffectLimit = 3
// Стартовые значения и разброс угла в каждую сторону каждого даммика
constant real WaterDragon_StartDistance = 1000
constant real WaterDragon_StartSpeed = 900
constant real WaterDragon_StartRange = 100
constant real WaterDragon_StartDamage = 100
constant real WaterDragon_StartOffset = 75
constant real WaterDragon_StartScale = 1.5
constant real WaterDragon_AngleScatter = 8
// Множители и Делители
constant real WaterDragon_DistanceMultiplier = 10
constant real WaterDragon_SpeedMultiplier = 10
constant real WaterDragon_RangeMultiplier = 1
constant real WaterDragon_DamageMultiplier = 2
constant real WaterDragon_ScaleDivisor = 100
endglobals
native UnitAlive takes unit id returns boolean
function WaterDragonPreparation_EffectTimer takes nothing returns nothing
set Timer = GetExpiredTimer()
set TimerId = GetHandleId( Timer )
set Dummy = LoadUnitHandle( HT, TimerId, 'efct' )
set Alpha = LoadInteger( HT, TimerId, 'alph' ) - WaterDragon_AlphaRemovingSpeed
call SaveInteger( HT, TimerId, 'alph', Alpha )
call SetUnitVertexColor( Dummy, 255, 255, 255, Alpha )
if Alpha <= 0 then
call RemoveUnit( Dummy )
call PauseTimer( Timer )
call DestroyTimer( Timer )
call FlushChildHashtable( HT, TimerId )
endif
endfunction
function WaterDragonPreparation_Timer takes nothing returns nothing
set Timer = GetExpiredTimer()
set TimerId = GetHandleId( Timer )
set Caster = LoadUnitHandle( HT, TimerId, 'cstr' )
if GetUnitCurrentOrder( Caster ) == OrderId( WaterDragon_OrderString ) then
set Tick = LoadInteger( HT, TimerId, 'tick' ) + 1
call SaveInteger( HT, TimerId, 'tick', Tick )
call SaveInteger( HT, GetHandleId( Caster ), 'chrg', Tick )
call DisplayTimedTextToPlayer( GetOwningPlayer( Caster ), 0, 0, WaterDragon_ChargeTextDuration, WaterDragon_ChargeText + I2S( Tick ) + "%" )
else
set CasterId = GetHandleId( Caster )
set Tick = LoadInteger( HT, CasterId, 'tick' )
if not LoadBoolean( HT, TimerId, 'flag' ) then
set FastTimer = CreateTimer()
set FastTimerId = GetHandleId( FastTimer )
call SaveUnitHandle( HT, FastTimerId, 'efct', LoadUnitHandle( HT, TimerId, 'efct' ) )
call SaveInteger( HT, FastTimerId, 'alph', 255 )
call TimerStart( FastTimer, 0.03, true, function WaterDragonPreparation_EffectTimer )
set Tick = WaterDragon_TimeLeftForCast + 1
call SaveInteger( HT, CasterId, 'tick', Tick )
call SaveBoolean( HT, TimerId, 'flag', true )
call PauseTimer( Timer )
call TimerStart( Timer, 1, true, function WaterDragonPreparation_Timer )
endif
if not LoadBoolean( HT, CasterId, 'flag' ) then
set Tick = Tick - 1
call SaveInteger( HT, CasterId, 'tick', Tick )
call DisplayTimedTextToPlayer( GetOwningPlayer( Caster ), 0, 0, WaterDragon_TimeTextDuration, WaterDragon_TimeText + I2S( Tick ) + " Seconds" )
endif
if Tick <= 0 then
set CasterOwner = GetOwningPlayer( Caster )
call SetPlayerAbilityAvailable( CasterOwner, WaterDragon_SpellShotId, false )
call SetPlayerAbilityAvailable( CasterOwner, WaterDragon_SpellPreparationId, true )
call PauseTimer( Timer )
call DestroyTimer( Timer )
call FlushChildHashtable( HT, TimerId )
call FlushChildHashtable( HT, CasterId )
endif
endif
endfunction
function WaterDragonShot_Group takes nothing returns nothing
set EnumUnit = GetEnumUnit()
if IsUnitInRangeXY( EnumUnit, NewX, NewY, Range ) then
if IsUnitInGroup( EnumUnit, FastGroup ) then
return
endif
if not UnitAlive( EnumUnit ) then
return
endif
if not IsUnitEnemy( EnumUnit, GetOwningPlayer( Caster ) ) then
return
endif
if IsUnitType( EnumUnit, UNIT_TYPE_STRUCTURE ) then
return
endif
call UnitDamageTarget( Caster, EnumUnit, LoadReal( HT, TimerId, 'damg' ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS )
call GroupAddUnit( FastGroup, EnumUnit )
endif
endfunction
function WaterDragonShot_Move takes unit dummy, real startX, real startY, real endX, real endY returns nothing
set NewX = startX * ( 1 - Time ) + endX * Time
set NewY = startY * ( 1 - Time ) + endY * Time
if Tick == ( Tick / WaterDragon_EffectLimit ) * WaterDragon_EffectLimit then
call DestroyEffect( AddSpecialEffect( WaterDragon_MoveEffectPath, NewX, NewY ) )
endif
call SetUnitX( dummy, NewX )
call SetUnitY( dummy, NewY )
call GroupEnumUnitsInRange( Group, NewX, NewY, Range + 200, null ) // Добавляем 200, чтобы выделить юнитов учитывая их физический размер через IsUnitInRangeXY, так как GroupEnum проверяет только центр юнита, а IsUnitInRangeXY — ещё и его физический размер.
call ForGroup( Group, function WaterDragonShot_Group )
call GroupClear( Group )
if Time >= 1 then
call RemoveUnit( dummy )
endif
endfunction
function WaterDragonShot_Timer takes nothing returns nothing
set Timer = GetExpiredTimer()
set TimerId = GetHandleId( Timer )
set Caster = LoadUnitHandle( HT, TimerId, 'cstr' )
set FastGroup = LoadGroupHandle( HT, TimerId, 'grup' )
set Range = LoadReal( HT, TimerId, 'rang' )
set Tick = LoadInteger( HT, TimerId, 'tick' ) + 1
call SaveInteger( HT, TimerId, 'tick', Tick )
set Time = ( Tick * WaterDragon_TimerPeriod ) / ( LoadReal( HT, TimerId, 'dist' ) / LoadReal( HT, TimerId, 'sped' ) )
call WaterDragonShot_Move( LoadUnitHandle( HT, TimerId, 'dmy1' ), LoadReal( HT, TimerId, 'RDSX' ), LoadReal( HT, TimerId, 'RDSY' ), LoadReal( HT, TimerId, 'RDEX' ), LoadReal( HT, TimerId, 'RDEY' ) )
call WaterDragonShot_Move( LoadUnitHandle( HT, TimerId, 'dmy2' ), LoadReal( HT, TimerId, 'LDSX' ), LoadReal( HT, TimerId, 'LDSY' ), LoadReal( HT, TimerId, 'LDEX' ), LoadReal( HT, TimerId, 'LDEY' ) )
if Time >= 1 then
call GroupClear( FastGroup )
call DestroyGroup( FastGroup )
call PauseTimer( Timer )
call DestroyTimer( Timer )
call FlushChildHashtable( HT, TimerId )
call SaveInteger( HT, GetHandleId( Caster ), 'tick', 0 )
endif
endfunction
function WaterDragon_Handler takes nothing returns nothing
if GetSpellAbilityId() == WaterDragon_SpellPreparationId then
set Caster = GetTriggerUnit()
set CasterOwner = GetOwningPlayer( Caster )
set Timer = CreateTimer()
set TimerId = GetHandleId( Timer )
call SetPlayerAbilityAvailable( CasterOwner, WaterDragon_SpellPreparationId, false )
call SetPlayerAbilityAvailable( CasterOwner, WaterDragon_SpellShotId, true )
call SaveUnitHandle( HT, TimerId, 'cstr', Caster )
call SaveUnitHandle( HT, TimerId, 'efct', CreateUnit( CasterOwner, WaterDragon_PreparationDummyId, GetUnitX( Caster ), GetUnitY( Caster ), GetRandomReal( 0, 360 ) ) )
call TimerStart( Timer, WaterDragon_PreparationTime * 0.01, true, function WaterDragonPreparation_Timer )
endif
if GetSpellAbilityId() == WaterDragon_SpellShotId then
set Caster = GetTriggerUnit()
set CasterId = GetHandleId( Caster )
set CasterOwner = GetOwningPlayer( Caster )
set Charge = I2R( LoadInteger( HT, CasterId, 'chrg' ) )
set CasterX = GetUnitX( Caster )
set CasterY = GetUnitY( Caster )
set Angle = Atan2( GetSpellTargetY() - CasterY, GetSpellTargetX() - CasterX ) * bj_RADTODEG // Конвертирую в градусы что-бы не было возни с радианами при создании даммиков
set Distance = WaterDragon_StartDistance + Charge * WaterDragon_DistanceMultiplier
set Scale = WaterDragon_StartScale + Charge / WaterDragon_ScaleDivisor
set Timer = CreateTimer()
set TimerId = GetHandleId( Timer )
call SetPlayerAbilityAvailable( CasterOwner, WaterDragon_SpellShotId, false )
call SetPlayerAbilityAvailable( CasterOwner, WaterDragon_SpellPreparationId, true )
call SaveUnitHandle( HT, TimerId, 'cstr', Caster )
call SaveGroupHandle( HT, TimerId, 'grup', CreateGroup() )
call SaveBoolean( HT, CasterId, 'flag', true )
call SaveReal( HT, TimerId, 'dist', Distance )
call SaveReal( HT, TimerId, 'sped', WaterDragon_StartSpeed + Charge * WaterDragon_SpeedMultiplier )
call SaveReal( HT, TimerId, 'damg', WaterDragon_StartDamage + Charge * WaterDragon_DamageMultiplier )
call SaveReal( HT, TimerId, 'rang', WaterDragon_StartRange + Charge * WaterDragon_RangeMultiplier )
set FastAngle = ( Angle + WaterDragon_AngleScatter ) * bj_DEGTORAD
set StartX = CasterX + WaterDragon_StartOffset * Cos( FastAngle )
set StartY = CasterY + WaterDragon_StartOffset * Sin( FastAngle )
set Dummy = CreateUnit( CasterOwner, WaterDragon_DummyId, StartX, StartY, FastAngle * bj_RADTODEG )
call SetUnitScale( Dummy, Scale, Scale, Scale )
call SaveUnitHandle( HT, TimerId, 'dmy1', Dummy )
call SaveReal( HT, TimerId, 'RDSX', StartX ) // Right Dummy Start X
call SaveReal( HT, TimerId, 'RDSY', StartY ) // Right Dummy Start Y
call SaveReal( HT, TimerId, 'RDEX', StartX + Distance * Cos( FastAngle ) ) // Right Dummy End X
call SaveReal( HT, TimerId, 'RDEY', StartY + Distance * Sin( FastAngle ) ) // Right Dummy End Y
set FastAngle = ( Angle - WaterDragon_AngleScatter ) * bj_DEGTORAD
set StartX = CasterX + WaterDragon_StartOffset * Cos( FastAngle )
set StartY = CasterY + WaterDragon_StartOffset * Sin( FastAngle )
set Dummy = CreateUnit( CasterOwner, WaterDragon_DummyId, StartX, StartY, FastAngle * bj_RADTODEG )
call SetUnitScale( Dummy, Scale, Scale, Scale )
call SaveUnitHandle( HT, TimerId, 'dmy2', Dummy )
call SaveReal( HT, TimerId, 'LDSX', StartX ) // Left Dummy Start X
call SaveReal( HT, TimerId, 'LDSY', StartY ) // Left Dummy Start Y
call SaveReal( HT, TimerId, 'LDEX', StartX + Distance * Cos( FastAngle ) ) // Left Dummy EndX X
call SaveReal( HT, TimerId, 'LDEY', StartY + Distance * Sin( FastAngle ) ) // Left Dummy EndY Y
call TimerStart( Timer, WaterDragon_TimerPeriod, true, function WaterDragonShot_Timer )
endif
endfunction
function InitTrig_WaterDragon takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent( t, Player( i ), EVENT_PLAYER_UNIT_SPELL_EFFECT, null )
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction( t, function WaterDragon_Handler )
set t = null
endfunction