Не знаю, нужно ли создавать новый вопрос, вообщем пишу сюда.
Подредактировал свой код под ваши указания, и карта перестала фаталится. Но обнаружилась другая проблема: сперва всё работает как надо, но в один момент снова начинается цепная реакция (рекурсия, но это не точно), но уже не фаталит, а просто убивает юнита. Дальше всё снова начинает работать как надо, но не надолго. После нескольких нормальных срабатываний триггера, срабатывает 1 с рекурсией, и всё по-новой.
scope StormHammer initializer Initialization
globals
public constant integer STORM_HAMMER = 'A019'
public constant string AOE_EFFECT_PATH = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
public constant string TARGET_EFFECT_PATH = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
public constant string LIGHTNING_NAME = "CLPB"
public constant real LIGHTNING_HEIGHT = 9900.0
public constant real LIGHTNING_LIFE_TIME = 0.1
public constant real STORM_HAMMER_SLOW_DURATION = 1.2
public constant integer STORM_HAMMER_SLOW_PERCENT = 92
public constant boolean ATTACK_FLAG = false
public constant boolean RANGED_FLAG = false
public constant attacktype ATTACK_TYPE = ATTACK_TYPE_CHAOS
public constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL
public constant weapontype WEAPON_TYPE = null
endglobals
public constant function GetAbilityRadius takes integer abilityLevel returns real
return 475.0 + 25.0 * abilityLevel
endfunction
public constant function GetAbilityDamage takes integer abilityLevel returns real
return 25.0 * abilityLevel
endfunction
public function IsUnitAlive takes unit whichUnit returns boolean
return ( not IsUnitType( whichUnit, UNIT_TYPE_DEAD ) ) and ( GetUnitTypeId( whichUnit ) != 0 )
endfunction
globals
public constant group TEMP_GROUP = CreateGroup( )
public constant trigger TRIGGER = CreateTrigger( )
public constant hashtable HASHTABLE = InitHashtable( )
public boolexpr boolexprForGroup = null
public boolean tempBool = true
endglobals
public function Conditions takes nothing returns boolean
local unit victimUnit = GetTriggerUnit( )
local unit attackingUnit = GetEventDamageSource( )
local integer abilityLevel = GetUnitAbilityLevel( attackingUnit, STORM_HAMMER )
// local real currentMana = GetUnitState( attackingUnit, UNIT_STATE_MANA )
// local real abilityManaCost = GetAbilityManaCost( abilityLevel )
local boolean a = ( abilityLevel >= 1 )
// local boolean b = ( currentMana >= abilityManaCost )
// local boolean c = ( not IsAbilityOnCooldown( GetUnitAbility( attackingUnit, STORM_HAMMER ) ) )
local boolean d = ( IsUnitEnemy( attackingUnit, GetOwningPlayer( victimUnit ) ) )
local boolean f = ( IsUnitAlive( victimUnit ) )
set attackingUnit = null
set victimUnit = null
return ( tempBool ) and ( a ) and ( d ) and ( f ) // and ( c ) and ( d )
endfunction
public function GroupCallback takes nothing returns boolean
local unit filterUnit = GetFilterUnit( )
local unit attackingUnit = GetEventDamageSource( )
local player attackingUnitOwner = GetOwningPlayer( attackingUnit )
local boolean a = ( not IsUnitType( filterUnit, UNIT_TYPE_STRUCTURE ) )
local boolean b = ( not IsUnitType( filterUnit, UNIT_TYPE_MECHANICAL ) )
local boolean c = ( not IsUnitType( filterUnit, UNIT_TYPE_MAGIC_IMMUNE ) )
local boolean d = ( IsUnitEnemy(filterUnit, GetOwningPlayer( attackingUnit ) ) )
local boolean e = ( IsUnitAlive( filterUnit ) )
if ( tempBool ) and ( a ) and ( b ) and ( c ) and ( d ) and ( e ) then
call DestroyEffect( AddSpecialEffectTarget( TARGET_EFFECT_PATH, filterUnit, "origin" ) )
// call SlowUnit( filterUnit, STORM_HAMMER_SLOW_PERCENT, STORM_HAMMER_SLOW_DURATION )
set tempBool = false
call UnitDamageTarget( attackingUnit, filterUnit, GetAbilityDamage( GetUnitAbilityLevel( attackingUnit, STORM_HAMMER ) ), ATTACK_FLAG, RANGED_FLAG, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE )
set tempBool = true
endif
set filterUnit = null
set attackingUnit = null
return false
endfunction
public function Actions takes nothing returns nothing
local unit victim = GetTriggerUnit( )
local unit attacker = GetEventDamageSource( )
local real victimZ = GetUnitFlyHeight( victim )
local real victimX = GetUnitX( victim )
local real victimY = GetUnitY( victim )
local integer abilityLevel = GetUnitAbilityLevel( attacker, STORM_HAMMER )
// local integer abilityManaCost = GetAbilityManaCost( abilityLevel )
// local real abilityCooldown = GetAbilityDataCooldown( GetUnitAbility( attacker, STORM_HAMMER ), abilityLevel )
// local real newManaState = GetUnitState( attacker, UNIT_STATE_MANA ) - abilityManaCost
call SaveInteger( HASHTABLE, GetHandleId( attacker ), STORM_HAMMER, LoadInteger( HASHTABLE, GetHandleId( attacker ), STORM_HAMMER ) + 1 )
call CreateFloatingTextTag( GetOwningPlayer( attacker ), FLOATING_TEXTTAG_CRITICAL_STRIKE, LoadInteger( HASHTABLE, GetHandleId( attacker ), STORM_HAMMER ), GetUnitX( attacker ), GetUnitY( attacker ) )
if ( LoadInteger( HASHTABLE, GetHandleId( attacker ), STORM_HAMMER ) >= 1 ) then
call SaveInteger( HASHTABLE, GetHandleId( attacker ), STORM_HAMMER, 0 )
// call IssueImmediateOrder( attacker, "stop" )
// call StartAbilityCooldown( attacker, STORM_HAMMER, 1 )
// call SetUnitState( attacker, UNIT_STATE_MANA, newManaState )
call GroupEnumUnitsInRange( TEMP_GROUP, victimX, victimY, GetAbilityRadius( abilityLevel ), boolexprForGroup )
// call DestroyLightningTimed( AddLightningEx( LIGHTNING_NAME, true, victimX, victimY, LIGHTNING_HEIGHT, victimX, victimY, victimZ ), LIGHTNING_LIFE_TIME )
call DestroyEffect( AddSpecialEffectTarget( AOE_EFFECT_PATH, victim, "origin" ) )
endif
set victim = null
set attacker = null
endfunction
public function Initialization takes nothing returns nothing
set boolexprForGroup = Condition(function GroupCallback)
call PreloadAbility( STORM_HAMMER )
call PreloadEffect( AOE_EFFECT_PATH )
call PreloadEffect( TARGET_EFFECT_PATH )
call PreloadLightning( LIGHTNING_NAME )
// call TriggerRegisterAnyUnitEventBJ( TRIGGER, EVENT_PLAYER_UNIT_ATTACKED ) // данный триггер запускается извне с событием EVENT_UNIT_DAMAGED.
call TriggerAddCondition( TRIGGER, Condition( function StormHammer_Conditions ) )
call TriggerAddAction( TRIGGER, function StormHammer_Actions )
endfunction
endscope
quq_CCCP, а почему рекурсия не происходит, когда юниту наносится смертельный урон, ведь какой-бы величной не обладал нанесённый урон, он должен нанестись через фрейм. P.S: статью еще не прочёл.
function Trig_BloodRageEffect_Actions takes nothing returns boolean
local trigger TempTrigger = GetTriggeringTrigger( )
local integer id = GetHandleId( TempTrigger )
local unit BloodSeeker = ( LoadUnitHandle( udg__htb_DATA, ( id ), ( 2 ) ) )
local unit Target = ( LoadUnitHandle( udg__htb_DATA, ( id ), ( 17 ) ) )
local integer RageLevel = GetUnitAbilityLevel( BloodSeeker, 'A311' )
if GetTriggerEventId( ) == EVENT_UNIT_DAMAGED then
if udg_IsDamaged and( Target == GetEventDamageSource( )or Target == GetTriggerUnit( ) ) then
set udg_IsDamaged = false
call P6I( GetEventDamageSource( ), GetTriggerUnit( ), 3, GetEventDamage( ) * ( 20 + 5 * RageLevel ) / 100 ) //P6I функция нанесения урона
set udg_IsDamaged = true
endif
elseif GetTriggerEventId( ) == EVENT_UNIT_DEATH then
if GetKillingUnit( ) == Target or GetTriggerUnit( ) == Target then
call SetUnitState( GetKillingUnit( ), UNIT_STATE_LIFE, GetUnitState( GetTriggerUnit( ), UNIT_STATE_MAX_LIFE ) * 0.25 + GetUnitState( GetKillingUnit( ), UNIT_STATE_LIFE ) )
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl", GetKillingUnit( ), "origin" ) )
elseif GetOwningPlayer( GetKillingUnit( ) ) == GetOwningPlayer( Target )and GetUnitAbilityLevel( GetKillingUnit( ), 'A04R' ) > 0 then
call SetUnitState( Target, UNIT_STATE_LIFE, GetUnitState( Target, UNIT_STATE_MAX_LIFE ) * 0.25 + GetUnitState( Target, UNIT_STATE_LIFE ) )
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl", Target, "origin" ) )
endif
if GetTriggerUnit( ) == Target then
call DestroyEffect( ( LoadEffectHandle( udg__htb_DATA, ( id ), ( 175 ) ) ) )
call DestroyEffect( ( LoadEffectHandle( udg__htb_DATA, ( id ), ( 176 ) ) ) )
call FlushChildHashtable( udg__htb_DATA, ( id ) )
call DestroyTrigger( TempTrigger ) //в оригинале используется функция SOI(...) из отдельной системы удаления триггеров
endif
else
call DestroyEffect( ( LoadEffectHandle( udg__htb_DATA, ( id ), ( 175 ) ) ) )
call DestroyEffect( ( LoadEffectHandle( udg__htb_DATA, ( id ), ( 176 ) ) ) )
call FlushChildHashtable( udg__htb_DATA, ( id ) )
call DestroyTrigger( TempTrigger )
endif
set TempTrigger = null
set BloodSeeker = null
set Target = null
return false
endfunction
запускается новый поток, который не нанесёт урон, возобновится работа текущего потока и переменная приравнивается к true
Чёрт,, почему это так гениально.?
avuremybe, мы конечно понимаем, что говоря бесконечность, Вы имели ввиду большое число. Но каким может быть это большое число? Сколько времени уходит на создание одного предмета (история предмета, характеристики, описание, триггерные способности у предмета, сама идея для предмета)? Мне кажется, довольно таки много..)))
А теперь представьте, что Вы сделали 1000 предметов. Вы когда нибудь видели карту с 1000 предметов? В той же доте (мне кажется, эта карта лидер по количеству предметов) около 100 предметов, а у Вас будет аж в десять раз больше, Карл!
Думаю, что, даже если Вы поставите лимит в 128 512 предметов, этого будет более чем достаточно..))
Всем спасибо за ответы, проблему я уже решил, дело было не в данной функции.
У меня была система, которая позволяла добавить событие "любой юнит атакован".
Также, был триггер, событие которого было как раз "любой юнит атакован".
В этом триггере триггерно наносился урон, который, естественно запускал этот триггер снова, и снова, и снова. Эдакая цепная реакция получалась.
Это и приводило к фаталу, хотя не понятно, почему фаталит... Цепная реакция должна сама ведь прекратиться, когда юнит умрёт. То есть, юниту наносится урон, потом еще, и еще, пока юнит не умрёт.
Или варик крашится, если триггер сам себя запускает без задержек по кд?
Думаю, лучше использовать GetUnitState(), а не GetWidgetLife(), потому что второе возвращает лишь текущее ХП, а процентный урон может быть как и от текущего ХП, так и от максимального ХП.
Maniac_91, я думаю можно без отключения триггера, после телепорта даешь юниту абилку пустышку, и убираешь ее, когда юнит покидает область телепорта. Таким образом, чтобы обратно вернуться, юниту необходимо после телепорта выйти из области , а затем снова войти в неё. А если отключить триггер, не смогут телепортироваться все юниты.
Первый удар - 10%
Второй удар - 20%
Третий удар - 30%
Четвёртый удар - 40% и т.д.
Шанс срабатывания растёт с каждым ударом, а в случае прока возвращается обратно на свои изначальные значения.
Понимаешь, была бы какая-нибудь задержка, и в отрывке времени сработало бы другое событие, твой GetTriggerUnit может быть другого юнита давал бы.
Мне кажется как раз переменные могут перезаписаться, если будет задержка. А GetTriggerUnit() привязан к потоку и перезаписаться не может, если я правильно всё понял.
Ред. scopterectus
» WarCraft 3 / Фаталит карта
» WarCraft 3 / Фаталит карта
» WarCraft 3 / Фаталит карта
Ред. scopterectus
» WarCraft 3 / Фаталит карта
P.S: статью еще не прочёл.
Чёрт,, почему это так гениально.?
Ред. scopterectus
» WarCraft 3 / Поиск элемента БД
128512 предметов, этого будет более чем достаточно..))» WarCraft 3 / Фаталит карта
Также, был триггер, событие которого было как раз "любой юнит атакован".
В этом триггере триггерно наносился урон, который, естественно запускал этот триггер снова, и снова, и снова. Эдакая цепная реакция получалась.
» WarCraft 3 / Скрыть индикатор загрузки
Ред. scopterectus
» WarCraft 3 / Поиск элемента БД
Ой, сори. тупанул. ))
» WarCraft 3 / Поиск элемента БД
Ред. scopterectus
» WarCraft 3 / Процентный урон
» WarCraft 3 / Поиск элемента БД
Ред. scopterectus
» WarCraft 3 / Поиск элемента БД
» WarCraft 3 / Один таймер
» WarCraft 3 / Как добавляются нативки?
Ред. scopterectus
» WarCraft 3 / Как добавляются нативки?
Ред. scopterectus
» WarCraft 3 / Иногда хеш таблица запаздывает???
Ред. scopterectus
» WarCraft 3 / Двухсторонний телепорт
» WarCraft 3 / Искусственный интеллект
» WarCraft 3 / Рандом Варкрафта и Абилки с шансом
» WarCraft 3 / Рандом Варкрафта и Абилки с шансом
Jinada Bounty Hunter'a из Dota имеет перезарядку, хоть и является пассивной способностью.
» WarCraft 3 / Триггеры и Нестандартные абилки
» WarCraft 3 / Рандом Варкрафта и Абилки с шансом
Второй удар - 20%
Третий удар - 30%
Четвёртый удар - 40% и т.д.
Шанс срабатывания растёт с каждым ударом, а в случае прока возвращается обратно на свои изначальные значения.
» WarCraft 3 / Передача данных в другую функцию для группы
» WarCraft 3 / Можно ли сделать способность у героя изначальной?
Ред. scopterectus
» WarCraft 3 / GetTriggerPlayer( )