Добавлен quq_CCCP,
не публикуется
Venomous Gale Venomanser'а из DotA в том виде в котором его реализовал IceFrog.
Из доты 6.83с с восстановленными именами функций и переменных.
Из доты 6.83с с восстановленными именами функций и переменных.
Вспомогательные системы IceFrog'а
DamageTarget
Фрог почему то ленится каждый раз писать тип атаки и урона, а вместо того пользуется заготовленной функцией с шаблонными типами урона.
function UnitDamageEnemy takes unit P7I,unit P8I,integer P9I,real PAI returns nothing
if P9I==0 then
return
endif
if P9I==1 then
call UnitDamageTarget(P7I,P8I,PAI,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE,WEAPON_TYPE_WHOKNOWS)
elseif P9I==2 then
call UnitDamageTarget(P7I,P8I,PAI,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
elseif P9I==3 then
call UnitDamageTarget(P7I,P8I,PAI,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_MAGIC,WEAPON_TYPE_WHOKNOWS)
elseif P9I==4 then
call UnitDamageTarget(P7I,P8I,PAI,true,true,ATTACK_TYPE_PIERCE,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
elseif P9I==5 then
call UnitDamageTarget(P7I,P8I,PAI,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
elseif P9I==6 then
call SetUnitState(P8I,UNIT_STATE_LIFE,RMaxBJ(GetUnitState(P8I,UNIT_STATE_LIFE)-PAI,1))
if GetUnitState(P8I,UNIT_STATE_LIFE)<2 then
call UnitRemoveBuffs(P8I,true,true)
call UnitRemoveAbility(P8I,'Aetl')
call UnitDamageTarget(CreateUnit(GetOwningPlayer(P7I),'e00E',0,0,0),P8I,100000000.00,true,false,ATTACK_TYPE_MELEE,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
endif
elseif P9I==7 then
if GetUnitAbilityLevel(P8I,'Aetl')>0 or GetUnitAbilityLevel(P8I,'B01N')>0 then
call UnitDamageTarget(P7I,P8I,PAI,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_MAGIC,WEAPON_TYPE_WHOKNOWS)
else
call UnitDamageTarget(P7I,P8I,PAI,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
endif
elseif P9I==8 then
call UnitDamageTarget(P7I,P8I,PAI,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
endif
endfunction
GroupUtils
Кто то надаумил фрога использовать ресайклы групп...
library GroupUtils
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a simple implementation of a stack for groups that need to
//* be in the user's control for greater than an instant of time. Additionally,
//* this library provides a single, global group variable for use with user-end
//* enumerations. It is important to note that users should not be calling
//* DestroyGroup() on the global group, since then it may not exist for when it
//* it is next needed.
//*
//* The group stack removes the need for destroying groups and replaces it with
//* a recycling method.
//* function NewGroup takes nothing returns group
//* function ReleaseGroup takes group g returns boolean
//* function GroupRefresh takes group g returns nothing
//*
//* NewGroup grabs a currently unused group from the stack or creates one if the
//* stack is empty. You can use this group however you'd like, but always
//* remember to call ReleaseGroup on it when you are done with it. If you don't
//* release it, it will 'leak' and your stack may eventually overflow if you
//* keep doing that.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hash table. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it.
//*
globals
//* Group for use with all instant enumerations
group ENUM_GROUP = CreateGroup()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Assorted constants
private constant integer MAX_HANDLE_COUNT = 408000
private constant integer MIN_HANDLE_ID = 0x100000
//* Arrays and counter for the group stack
private group array Groups
private integer array Status[MAX_HANDLE_COUNT]
private integer Count = 0
endglobals
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
set Status[GetHandleId(Groups[Count])-MIN_HANDLE_ID] = 1
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer stat = Status[GetHandleId(g)-MIN_HANDLE_ID]
local boolean b = true
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Null groups cannot be released")
set b = false
elseif stat == 0 then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Group not part of stack")
set b = false
elseif stat == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Groups cannot be multiply released")
set b = false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Max groups achieved, destroying group")
call DestroyGroup(g)
set b = false
else
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
set Status[GetHandleId(g)-MIN_HANDLE_ID] = 2
endif
return b
endfunction
endlibrary
Trigger Remover
Любовь фрога к триггерам дает свои плоды...
Собственно кто то написал систему удаления триггеров чтобы не было багов коллизии хендлов триггеров, но явно не фрог.
Собственно кто то написал систему удаления триггеров чтобы не было багов коллизии хендлов триггеров, но явно не фрог.
globals
timer DispTimer = null
integer nTriggerIndex = 0
trigger array DispTriggers
real array Elapsed
boolean udg_ItsForDebug = true
endglobals
function ClenTrigger_ERROR takes nothing returns nothing
local integer nPlayerIndex = 0
if udg_ItsForDebug then
loop
call DisplayTimedTextToPlayer( Player( nPlayerIndex ), 0, 0, 120, "|c00ff0303Что то пошло нетак!|r" )
call DisplayTimedTextToPlayer( Player( nPlayerIndex ), 0, 0, 120, "|c00ff0303Это все фигня, ни какайте в трусы, этот баг несерьезен!|r" )
call DisplayTimedTextToPlayer( Player( nPlayerIndex ), 0, 0, 120, "|c00ff0303Не забудьте сохранить реплей, а так же не поленитесь отправить его мне на мыло IceFrog@gmail.com|r" )
set nPlayerIndex = nPlayerIndex + 1
exitwhen nPlayerIndex == 12
endloop
endif
endfunction
function CleanTrigger_GetTime takes nothing returns real // зачем он обьявил эту функцию?
return TimerGetElapsed( DispTimer ) // так как она не где не используется оптимизатор не стер её оригинальное имя
endfunction
function DisposeTrigger takes trigger t returns nothing
call DisableTrigger( t )
set nTriggerIndex = nTriggerIndex + 1
set DispTriggers[nTriggerIndex] = t
set Elapsed[nTriggerIndex] = TimerGetElapsed( DispTimer ) + 60
if nTriggerIndex > 8000 then
call ClenTrigger_ERROR( )
endif
endfunction
function CleanTriggerArray takes integer nIndex returns nothing
if nIndex != nTriggerIndex then
set DispTriggers[nIndex] = DispTriggers[nTriggerIndex]
set Elapsed[nIndex] = Elapsed[nTriggerIndex]
endif
set DispTriggers[nTriggerIndex] = null
set Elapsed[nTriggerIndex] = 0
set nTriggerIndex = nTriggerIndex - 1
endfunction
function Trig_Trigger_Remover_Actions takes nothing returns nothing
local real CleanTime = TimerGetElapsed( DispTimer )
local integer nIndex = 1
loop
exitwhen nIndex > nTriggerIndex
if Elapsed[nIndex] < CleanTime then
if DispTriggers[nIndex] == null or IsTriggerEnabled( DispTriggers[nIndex] ) == true then
call ClenTrigger_ERROR( )
else
call DestroyTrigger( DispTriggers[nIndex] )
endif
call CleanTriggerArray( nIndex )
else
set nIndex = nIndex + 1
endif
endloop
return
endfunction
//===========================================================================
function InitTrig_Trigger_Remover takes nothing returns nothing
set gg_trg_Trigger_Remover = CreateTrigger( )
set DispTimer = CreateTimer( )
call TimerStart( DispTimer, 999999999999.00, false, null )
call TriggerRegisterTimerEvent( gg_trg_Trigger_Remover, 15.00, true )
call TriggerAddAction( gg_trg_Trigger_Remover, function Trig_Trigger_Remover_Actions )
endfunction
Venomus Gale
Код способности
function AddTextTagTarget takes string UWI,real M5I,unit UXI,real UJI,integer r,integer g,integer b,integer a returns nothing
local texttag tt=CreateTextTag()
call SetTextTagText(tt,UWI,UJI)
call SetTextTagPosUnit(tt,UXI,64)
call SetTextTagColor(tt,r,g,b,a)
call SetTextTagVelocity(tt,0,0.0355)
call SetTextTagFadepoint(tt,2)
call SetTextTagPermanent(tt,false)
call SetTextTagLifespan(tt,M5I)
if IsUnitVisible(UXI,GetLocalPlayer()) then //or P0I(GetLocalPlayer())then
call SetTextTagVisibility(tt,true)
else
call SetTextTagVisibility(tt,false)
endif
set tt=null
endfunction
function UnitAddPremanentAbility takes unit whichunit,integer id returns nothing // позволяет не терять при морфах способности добавленные UnitAddAbility.
call UnitAddAbility(whichunit,id)
call UnitMakeAbilityPermanent(whichunit,true,id)
endfunction
function IsUnitDead takes unit u returns boolean
return IsUnitType( u, UNIT_TYPE_DEAD ) or GetUnitTypeId( u ) < 1
endfunction
function GaleAvalibleTargets_Cond takes nothing returns boolean // фильтр для группы Venomus Gale
// Допустимы цели - враги, без скилла 'A04R' (маркер курьера и осадных войск), не здания, живые.
return IsUnitEnemy( udg_FilterUnit, GetOwningPlayer( GetFilterUnit( ) ) )and( GetUnitAbilityLevel( GetFilterUnit( ), 'A04R' ) == 0 and IsUnitType( GetFilterUnit( ), UNIT_TYPE_STRUCTURE ) == false and IsUnitDead( GetFilterUnit( ) ) == false )
endfunction
function PlaySoundAtCord takes sound Snd, real x, real y returns nothing // проигрывает некий звук в указанных координатах.
call SetSoundPosition( Snd, x, y, 0 )
call SetSoundVolume( Snd, 127 )
set bj_lastPlayedSound = Snd
if ( Snd != null ) then
call StartSound( Snd )
endif
endfunction
function abp takes real xa, real xb, real ya, real yb returns real // находит угол между точками координатами точек в градусах.
return 57.295827 * Atan2( yb - ya, xb - xa )
endfunction
function Gale_Damage_Enemy takes nothing returns boolean
local trigger trig = GetTriggeringTrigger( )
local integer TrigId = GetHandleId( trig )
local unit Attacker = ( LoadUnitHandle( udg_data, ( TrigId ), ( 2 ) ) )
local unit Enemy = ( LoadUnitHandle( udg_data, ( TrigId ), ( 17 ) ) )
local integer level = ( LoadInteger( udg_data, ( TrigId ), ( 5 ) ) )
// проверка того что истекло время, с юнита рассеяли 'BEsh' (в оригинале 'B0AQ') или юнит умер (смертью считаеся даже юниты с Aegis of the Immortal или аналогом)
if GetTriggerEvalCount( trig ) > 5 or GetUnitAbilityLevel( Enemy, 'BEsh' ) == 0 or GetTriggerEventId( ) == EVENT_WIDGET_DEATH then
call DisposeTrigger( trig ) // функция удаления триггеров, из системы вероятно написанной Вексом, советую посмотреть вспомогательные системы выше.
call FlushChildHashtable( udg_data, ( TrigId ) )
else
call UnitDamageEnemy( Attacker, Enemy, 1, 30 * level - 30 )
// если уровень больше 1 то создает триггер наносящий переодический урон.
// наносит урон по формуле 30 * уровень - 30.
// тип урона ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE - обычное заклинание.
call AddTextTagTarget( I2S( 30 * level - 30 ), 3, Enemy, 0.025, 160, 255, 0, 230 )
// Создает текстаг над головой цели, внешне похожый на обычный Shadow Strike.
endif
set trig = null
set Attacker = null
set Enemy = null
return false
endfunction
function UnitAddGale takes unit Attacker, unit Enemy, integer level returns nothing // поражает юнитов 'A17N', так же создавая триггер следящий за целью и наносящим урон.
local unit Caster = CreateUnit( GetOwningPlayer( Enemy ), 'hdum', GetUnitX( Enemy ), GetUnitY( Enemy ), 0 ) // в оригинале 'e00E' - обычный дамми юнит.
local trigger trig
local integer TrigId
// 'A17N' - обычный Shadow Strike (Отравленный нож), урон обнулен, нужен только для замедления.
call UnitAddPremanentAbility( Caster, 'A17N' ) // фрог тронулся, дамми юнитов незачем морфить и потому способность у них не пропадет...
call SetUnitAbilityLevel( Caster, 'A17N', level )
if IssueTargetOrder( Caster, "shadowstrike", Enemy ) then
call UnitDamageEnemy( Attacker, Enemy, 1, 25 * level ) // наносит урон цели, тип урона ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE - обычное заклинание.
call AddTextTagTarget( I2S( 25 * level ) + "!", 3, Enemy, 0.025, 160, 255, 0, 230 ) // Создает текстаг над головой цели, внешне похожый на обычный Shadow Strike.
if level > 1 then // если уровень больше 1 то создает триггер наносящий переодический урон.
// наносит урон по формуле 30 * уровень - 30.
// тип урона ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE - обычное заклинание.
set trig = CreateTrigger( )
set TrigId = GetHandleId( trig )
call TriggerRegisterTimerEvent( trig, 3, true )
call TriggerRegisterDeathEvent( trig, Enemy )
call TriggerAddCondition( trig, Condition( function Gale_Damage_Enemy ) ) // создает утечку типа triggercondition!
call SaveUnitHandle( udg_data, ( TrigId ), ( 2 ), ( Attacker ) )
call SaveUnitHandle( udg_data, ( TrigId ), ( 17 ), ( Enemy ) )
call SaveInteger( udg_data, ( TrigId ), ( 5 ), ( level ) )
set trig = null
endif
endif
set Caster = null
endfunction
function Gale_Pick_Enemy takes nothing returns nothing
local unit enemy = GetEnumUnit( )
if IsUnitInGroup( enemy, udg_TempGroup ) == false then
call UnitAddGale( udg_TempUnit, enemy, udg_TempInt )
call GroupAddUnit( udg_TempGroup, enemy )
endif
set enemy = null
endfunction
function Gale_Move_Timer_Expires takes nothing returns boolean // передвигает дамми юнита в сторону каста, так же ищет подходящих юнитов вокруг дамми.
local trigger trig = GetTriggeringTrigger( )
local integer TrigId = GetHandleId( trig )
local group grp = ( LoadGroupHandle( udg_data, ( TrigId ), ( 22 ) ) )
local unit DummyGale = ( LoadUnitHandle( udg_data, ( TrigId ), ( 19 ) ) )
local unit Caster = ( LoadUnitHandle( udg_data, ( TrigId ), ( 14 ) ) )
local integer level = ( LoadInteger( udg_data, ( TrigId ), ( 5 ) ) )
local real Ang = ( LoadReal( udg_data, ( TrigId ), ( 13 ) ) )
local group ExtraGroup
local real x
local real y
local real dx
local real dy
local real Dist = 30
local unit dummy
set udg_TempInt = level
if GetTriggerEvalCount( trig ) > 28 then
call ReleaseGroup( grp ) // в оригинале NSI( ) IceFrog использует систему внешне похожую на GroupUtils
call FlushChildHashtable( udg_data, ( TrigId ) )
call DisposeTrigger( trig ) // функция удаления триггеров, из системы вероятно написанной Вексом, советую посмотреть вспомогательные системы выше.
call ShowUnit( DummyGale, false )
call KillUnit( DummyGale )
else
set x = GetUnitX( DummyGale )
set y = GetUnitY( DummyGale )
set ExtraGroup = NewGroup( )
set udg_TempGroup = grp
set udg_FilterUnit = Caster
set udg_TempUnit = Caster
call GroupEnumUnitsInRange( ExtraGroup, x, y, 150.00, Condition( function GaleAvalibleTargets_Cond ) )
call ForGroup( ExtraGroup, function Gale_Pick_Enemy )
call ReleaseGroup( ExtraGroup ) // в оригинале NSI( ) IceFrog использует систему внешне похожую на GroupUtils.
set dx = ( x + Dist * Cos( Ang * bj_DEGTORAD ) ) // в оригинале PTI - из системы проверки координат.
set dy = ( y + Dist * Sin( Ang * bj_DEGTORAD ) ) // в оригинале PUI - из системы проверки координат.
call SetUnitX( DummyGale, dx )
call SetUnitY( DummyGale, dy )
if ModuloInteger( GetTriggerEvalCount( trig ), 3 ) == 0 then
set dummy = CreateUnit( GetOwningPlayer( DummyGale ), 'o01W', dx, dy, 0 ) // создает дамми юнитов для обзора над местностью.
call KillUnit( dummy )
set dummy = null
endif
endif
set trig = null
set grp = null
set ExtraGroup = null
set DummyGale = null
set Caster = null
return false
endfunction
function Trig_Venomous_Gale_Actions takes nothing returns nothing
local trigger trig = CreateTrigger( )
local integer TrigId = GetHandleId( trig )
local group grp = NewGroup( ) // в оригинале NTI( ) IceFrog использует систему внешне похожую на GroupUtils
local unit Caster = GetTriggerUnit( )
local location SpellTargetLoc = GetSpellTargetLoc( )
local real x1 = GetUnitX( Caster )
local real y1 = GetUnitY( Caster )
local real x2 = GetLocationX( SpellTargetLoc )
local real y2 = GetLocationY( SpellTargetLoc )
local real Ang = abp( x1, x2, y1, y2 ) // находит угол между координатами точек в градусах.
local integer level = GetUnitAbilityLevel( Caster, 'A173' )
local unit DummyGale = CreateUnit( GetOwningPlayer( Caster ), 'h07K', x1, y1, Ang )
call PlaySoundAtCord( null , x1, y1 ) // функция которая проигрывает звук "Shadow Strike", в оригинале ссылкой на звук служит переменная VE
call SaveUnitHandle( udg_data, ( TrigId ), ( 19 ), ( DummyGale ) )
call SaveInteger( udg_data, ( TrigId ), ( 5 ), ( level ) )
call SaveGroupHandle( udg_data, ( TrigId ), ( 22 ), ( grp ) )
call SaveReal( udg_data, ( TrigId ), ( 13 ), ( ( Ang ) * 1.0 ) )
call SaveUnitHandle( udg_data, ( TrigId ), ( 14 ), ( Caster ) )
call TriggerRegisterTimerEvent( trig, 0.025, true )
call TriggerAddCondition( trig, Condition( function Gale_Move_Timer_Expires ) ) // создает утечку типа triggercondition!
call RemoveLocation( SpellTargetLoc )
set trig = null
set DummyGale = null
set grp = null
set Caster = null
set SpellTargetLoc = null
endfunction
function Trig_Venomous_Gale_Conditions takes nothing returns boolean // проверка что юнит применил 'A173' ( Venomous Gale )
// 'A173'(ANcl - channel) - Venomous Gale
// Основано на канал
// Цель - точка
// Приказ - volcano
// Раз. цели: "Воздушные", "Враги", "Наземные".
if GetSpellAbilityId( ) == 'A173' then
call Trig_Venomous_Gale_Actions( )
endif
return false
endfunction
//===========================================================================
function InitTrig_Venomous_Gale takes nothing returns nothing // инициализация триггера, эта функция вызовется после старта карты
local trigger trig = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( trig , Condition( function Trig_Venomous_Gale_Conditions ) )
set trig = null
endfunction
ВНИМАНИЕ
В коде встречаются ошибки и недоработки, имейте это в виду если собираетесь использовать этот код
Все претензии по качеству кода прошу писать IceFrog
Все претензии по качеству кода прошу писать IceFrog
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Можешь создать триггер с уже существующим событием и условием\действием.
Фрог явно все это просил сделать векса (или кого то еще умного), не от хорошей жизни.