Почему-то карта фаталит, если нанести триггерно несмертельный урон юниту, который был обработан данной функцией:
library SetUnitMaxState initializer Init

    globals
//      The rawcode of the life ability:
        private    constant    integer    MAX_STATE_LIFE_ABILITY    =    'A013'
        
//      The rawcode of the mana ability:
        private    constant    integer    MAX_STATE_MANA_ABILITY    =    'A014'
        
//      The maximum power of two the abilitys use:
        private    constant    integer    MAX_STATE_MAX_POWER       =    8
    endglobals

    globals
        private integer array PowersOf2
    endglobals

    function SetUnitMaxState takes unit u, unitstate state, real newValue returns nothing
        local integer stateAbility
        local integer newVal = R2I(newValue)
        local integer i = MAX_STATE_MAX_POWER
        local integer offset
        
        if state == UNIT_STATE_MAX_LIFE then
            set stateAbility = MAX_STATE_LIFE_ABILITY
        elseif state == UNIT_STATE_MAX_MANA then
            set stateAbility = MAX_STATE_MANA_ABILITY
        else
            return
        endif
        
        set newVal = newVal - R2I(GetUnitState(u, state))
        
        if newVal > 0 then
            set offset = MAX_STATE_MAX_POWER + 3
        elseif newVal < 0 then
            set offset = 2
            set newVal = -newVal
        else
            return
        endif

        loop
            exitwhen newVal == 0 or i < 0
            if newVal >= PowersOf2[i] then
                call UnitAddAbility(u, stateAbility)
                call SetUnitAbilityLevel(u, stateAbility, offset + i)
                call UnitRemoveAbility(u, stateAbility)
                set newVal = newVal - PowersOf2[i]
            else
                set i = i - 1
            endif
        endloop
    endfunction

    function AddUnitMaxState takes unit u, unitstate state, real addValue returns nothing
        call SetUnitMaxState(u, state, GetUnitState(u, state) + addValue)
    endfunction

    private function Init takes nothing returns nothing
        local integer i = 1
        
        set PowersOf2[0] = 1
        loop
            set PowersOf2[i] = PowersOf2[i - 1] * 2
            set i = i + 1
            exitwhen i == MAX_STATE_MAX_POWER + 3
        endloop
    endfunction

endlibrary

ScopteRectuS, ну как я и догадывался, что идет рекурсия.
10 событий - юнит получает урон, на одного юнита... Нужны именно такого типа проверки, всегда в условии триггера проверяй от кого урон и какой этот урон с помощью флага глобалки как в примере.В блоге лича хорошо описаны костыли доты, почитай для общего развития чтобы не наступать на эти грабли еще раз.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
16
Игра имеет 32 слота под размещение данных вроде GetTriggerUnit()
Возможно, фатал случается, когда все 32 штуки заполняются из-за рекурсивного вызова, и идет попытка размещения поверх, ну либо какие-то еще внутренние структуры жестко ограничены сверху. Простой бесконечный цикл сам закрывается по истечению предоставленного лимита операций.
21
Не знаю, нужно ли создавать новый вопрос, вообщем пишу сюда.
Подредактировал свой код под ваши указания, и карта перестала фаталится. Но обнаружилась другая проблема: сперва всё работает как надо, но в один момент снова начинается цепная реакция (рекурсия, но это не точно), но уже не фаталит, а просто убивает юнита. Дальше всё снова начинает работать как надо, но не надолго. После нескольких нормальных срабатываний триггера, срабатывает 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
32
ScopteRectuS, как то ты события криво вешаешь, сразу по несколько на 1 юнита походу. Карту в студию.
21
    function RegisterUnitDamaged takes unit whichUnit returns nothing
        local integer unitId = GetHandleId( whichUnit )

        if HaveSavedHandle( REGISTER_UNIT_DAMAGED_HASHTABLE, unitId, HASHTABLE_FLAG_KEY ) then
//          call BJDebugMsg("TriggerRegisterDamagedEvent(...) :    Attempt to add new event.")

        else
            call SaveTriggerEventHandle( REGISTER_UNIT_DAMAGED_HASHTABLE, unitId, HASHTABLE_FLAG_KEY, TriggerRegisterUnitEvent( gg_trg_UnitDamaged, whichUnit, EVENT_UNIT_DAMAGED ) )
        endif
    endfunction
на одном юните не может быть более одного повешанного события.
Загруженные файлы
28
ScopteRectuS, что за костыль?
нафига вообще тут хештейбл
ты когда вызываешь эту функцию?
и вообще
готовых систем 100500
нафига свои костыли придумывать?
21
Готовые системы вешают событие на всех юнитов, а я сделал так, чтобы вешало лишь на тех, на кого мне нужно
library RegisterUnitDamaged

//  GetEventDamageSource() - Источник урона (атаковавший юнит).
//  GetEventDamage()       - Величина нанесённого урона.
//  GetTriggerUnit()       - Цель урона (атакованный юнит).

    globals
        public    constant    hashtable    REGISTER_UNIT_DAMAGED_HASHTABLE    =    InitHashtable( )
        public    constant    integer      HASHTABLE_FLAG_KEY                 =    0
    endglobals

    function RegisterUnitDamaged takes unit whichUnit returns nothing
        local integer unitId = GetHandleId( whichUnit )

        if HaveSavedHandle( REGISTER_UNIT_DAMAGED_HASHTABLE, unitId, HASHTABLE_FLAG_KEY ) then
//          call BJDebugMsg("TriggerRegisterDamagedEvent(...) :    Attempt to add new event.")

        else
            call SaveTriggerEventHandle( REGISTER_UNIT_DAMAGED_HASHTABLE, unitId, HASHTABLE_FLAG_KEY, TriggerRegisterUnitEvent( gg_trg_UnitDamaged, whichUnit, EVENT_UNIT_DAMAGED ) )
        endif
    endfunction

    public function Actions takes nothing returns nothing
        call ConditionalTriggerExecute( gg_trg_GreedIsGood )
        call ConditionalTriggerExecute( StormHammer_TRIGGER )
    endfunction

endlibrary

function InitTrig_UnitDamaged takes nothing returns nothing
    set gg_trg_UnitDamaged = CreateTrigger()
    call TriggerAddAction( gg_trg_UnitDamaged, function RegisterUnitDamaged_Actions )
endfunction
21
Не знаю, нужно ли создавать новый вопрос, вообщем пишу сюда.
Подредактировал свой код под ваши указания, и карта перестала фаталится. Но обнаружилась другая проблема: сперва всё работает как надо, но в один момент снова начинается цепная реакция (рекурсия, но это не точно), но уже не фаталит, а просто убивает юнита. Дальше всё снова начинает работать как надо, но не надолго. После нескольких нормальных срабатываний триггера, срабатывает 1 с рекурсией, и всё по-новой.
Причину бага я нашёл, это происходило потому что юниту снова наносился триггерный урон, но уже совсем в другом триггере.
    set udg_IsDamaged = false
    call UnitDamageTarget( whichUnit, target, amount, attack, ranged, attackType, damageType, weaponType )
    set udg_IsDamaged = true
28
ScopteRectuS, можно юзать дефайны
define UnitDamageTarget(whichUnit, target, amount, attack, ranged, attackType, damageType, weaponType ) ={
	udg_IsDamaged = false;
	call Unit##DamageTarget( whichUnit, target, amount, attack, ranged, attackType, damageType, weaponType );
	udg_IsDamaged = true;
}
вставь это в шапку карты и если я написал правильно то оно при компиляции заменит все UnitDamageTarget на код в фигурных скобках
32
ScopteRectuS, ну как я и догадывался, что идет рекурсия.
10 событий - юнит получает урон, на одного юнита... Нужны именно такого типа проверки, всегда в условии триггера проверяй от кого урон и какой этот урон с помощью флага глобалки как в примере.В блоге лича хорошо описаны костыли доты, почитай для общего развития чтобы не наступать на эти грабли еще раз.
Принятый ответ
22
а чем не угодил менять урон числом а потом уже наносить последный урон... А то события ловит каждый урон так и появилось рекурсия
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.