Почему-то карта фаталит, если нанести триггерно несмертельный урон юниту, который был обработан данной функцией:
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 событий - юнит получает урон, на одного юнита... Нужны именно такого типа проверки, всегда в условии триггера проверяй от кого урон и какой этот урон с помощью флага глобалки как в примере.В блоге лича хорошо описаны костыли доты, почитай для общего развития чтобы не наступать на эти грабли еще раз.

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
19
7 лет назад
0
Похожие вопросы:

ответ
Ну тут все очевидно, я абсолютно точно установил источник проблемы и нашел легкодоступное решение, специально для Вас.
Насколько я понимаю, мне совершенно не обязательно его описывать, так как Вы, справедливо полагая что Все люди на Земле, как и Вы, обладают экстрасенсорными способностями, можете подсмотреть его из моей головы.
ответ
почему так долго грузится карта
Потому что огромный Нестандартные объекты может тысяч или больше или Спелл герой до 100 уровень.
из них 60 загрузка просто висит на 1/5.
Если нетак? Проверь если есть файлы war3map.j папка Game\WarcraftIII, надо удалить файл. очень давно тоже 1 раз что за вылет или неправильно выполняет триггер.
Есть способы ускорить загрузку карты не экономя в редакторе объектов
Есть Widgetizer, там очень быстрая загрузка игра, но плохо работает спелл или текст.
ответ
Проблема решена.
ответ
Было создано 22 366 679 экземпляров класса CUnitListNode, которые заняли 255.9 МБ памяти.
При очередной попытке выделения, игра упала.
Виной всему утечки памяти: за 21 минуту набралось 80 тысяч групп и 20 тысяч точек.
Также, из-за выполнения большого количества кода, сильно лагает.
На стадии выбора героя (первые две минуты), выполняется 550 000 операций в секунду, а далее — 1 200 000.
Для сравнения: лимит потока — 300 000 операций.
Хорошо, что ты приложил карту, так как в логе маловато информации.

1
28
7 лет назад
Отредактирован nvc123
1
любой несмертельный урон?
даже если 1 единица урона?
1
16
7 лет назад
1
лог фатала приложи
1
29
7 лет назад
1
ScopteRectuS,
героям я бы не советовал таким способам хп менять, у меня были с этим фаталы, и я переделывал
0
21
7 лет назад
0
Всем спасибо за ответы, проблему я уже решил, дело было не в данной функции.
У меня была система, которая позволяла добавить событие "любой юнит атакован".
Также, был триггер, событие которого было как раз "любой юнит атакован".
В этом триггере триггерно наносился урон, который, естественно запускал этот триггер снова, и снова, и снова. Эдакая цепная реакция получалась.
Это и приводило к фаталу, хотя не понятно, почему фаталит... Цепная реакция должна сама ведь прекратиться, когда юнит умрёт. То есть, юниту наносится урон, потом еще, и еще, пока юнит не умрёт.
Или варик крашится, если триггер сам себя запускает без задержек по кд?
3
32
7 лет назад
Отредактирован quq_CCCP
3
ScopteRectuS, Дело в том что юнит неуспевает умереть, событие - юнит получает урон срабатывает до реального нанесения урона, т.е хп юнит потеряет или умрет только через фрейм, если на юнит повешано событие - юнит получает урон и в действии триггера ему еще раз наносят урон, происходит рекурсия, счетчик уронов на юнита переполняется, ну и фатал. Это хорошо описано в блоге драколича, где подробно описаны способности по блоку, ибо усиления урона. Можешь почитать на досуге и понять как лучше не делать способности.....
ScopteRectuS, думаю будет полезно ссылка
А вот сам код с пояснениями косяков ссылка
0
21
7 лет назад
Отредактирован scopterectus
0
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
			set udg_IsDamaged = false
            call P6I( GetEventDamageSource( ), GetTriggerUnit( ), 3, GetEventDamage( ) * ( 20 + 5 * RageLevel ) / 100 ) //P6I функция нанесения урона
            set udg_IsDamaged = true
            call P6I( GetEventDamageSource( ), GetTriggerUnit( ), 3, GetEventDamage( ) * ( 20 + 5 * RageLevel ) / 100 ) //P6I функция нанесения урона
запускается новый поток, который не нанесёт урон, возобновится работа текущего потока и переменная приравнивается к true
Чёрт,, почему это так гениально.?
0
16
7 лет назад
0
Игра имеет 32 слота под размещение данных вроде GetTriggerUnit()
Возможно, фатал случается, когда все 32 штуки заполняются из-за рекурсивного вызова, и идет попытка размещения поверх, ну либо какие-то еще внутренние структуры жестко ограничены сверху. Простой бесконечный цикл сам закрывается по истечению предоставленного лимита операций.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.