32

» WarCraft 3 / Юнит умирает при срабатывании триггера

Баг заключается что при вручении\удалении спеллбука происходит пересчет всех абилок, на фрейм они удаляются и добавляются снова, но из за бага абилки на здоровье удаляются дважды (точнее движок снимает бонус хп дважды, считая что абилка удаленная у юнита еще и удалилась у спелбука, т.е удалено 2 абилки) таким образом, у юнита становится максимум хп в 0 ед. и он умирает.
32

» WarCraft 3 / Создание юнитов

Yury13, Ну так ты проверять что в массиве не пустое место, не обязательно удалять юнита из массива, достаточно создать юнита и поместить его в группу, потом при выборе нового юнита из массива, проверить нет ли такого ид в группе юнитов, если есть, то искать снова, и так далее, ну и навсякий случай счетчик, если раз 10 не получилось, то создать конкретного.
32

» WarCraft 3 / Редактирование приказов

Это работает локально лишь у тебя, когда этот файл в папке с варом. По хорошему нужно либо в игровых константах искать, либо юзать сторонний софт который умеет изменять хоткеии на лету.
32

» WarCraft 3 / Анимация при создании юнита

Принятый ответ
Скорее всего кривая модель, к автору нужно обратится.
32

» WarCraft 3 / Hash в луа

Ельнур, а зачем тебе вовсе все это надо, если даже жасс сложно, мб гуи, простенькие дамми касты и все такое. конфетные войны, замок скиби - годные карты сделанные на гуи. Будет пахать на всех версиях в придачу.
32

» WarCraft 3 / конверт ордер defend в луа

ScorpioT1000, я чето больше доверяю людям которые сейчас работают, а не тогда, когда еще писали что ХТ супер медленные и там про таймер експлоит что топ, на деле оказалось что нет. Пруфы кстати приводили, и старые методики вроде посмотреть какой способ лагает меньше в игре, тот и быстрее - тоже оказались не корректными.

prog, про луа будем говорить когда будет разбор полетов на английском хотя-бы, что они и как сделали. Кто их знает, но про то что у них там не та реализайция и тормазнутее в разы - я уже слышал, сам на эту тему спорить не буду, поживем - увидим.

Почему ссыллки на старые темы все упали? На форуме ничего уже не почитать?
32

» WarCraft 3 / конверт ордер defend в луа

prog, В том то и дело, что сделали по минимуму, точнее просто свой интерпретатор по апи языка, на одну и ту же вирутальную машину. Но пока слухи, и перевод с китайского сленга -не читаем после гугл переводчика, позже если на хайве всплывет то уже и будем говорить что они сделали. Ссылку где обсирали луа китаезы и разбирали код игры дестабилизированный есть у анрайза.
32

» WarCraft 3 / конверт ордер defend в луа

Ельнур, быть может 'Ald0'?
В гуях укажи эту абилку, а потом конвертни в код скопируй рокод абилки.

prog, тут тоже кстати не тот луа, о котором все говорят. Но пока инфы на понятном языке нет (китайцы только), спорить с вами не буду.
32

» WarCraft 3 / конверт ордер defend в луа

prog, Бред, драколич и анрайз доказали обратное, у них одно адресное пространство, вовсе эти обьекты в вируальной машине практически не отличаются, ибо там можно создавать и удалять переменные на лету, поэтому нет никакой разницы. Чтение значения напрямую быстрее чем через переменную, речь идет о интерпретируемых языках а не о компилируемых.
32

» WarCraft 3 / Запрет на использование способности при условии

Ну либо вариант описанный выше prog,, либо сделать 2 способности, с одиаковым описанием но вторая не активна (что то требует) и менять их местами с помощью кода, удалять одну и вручать другую. Чтобы сохранялся кулдаун и прочие параметры - можно использовать способность "Aneg' - техника, меняя её уровни свапать ей 2 абилки, но работает она лишь у героев (у не героев фаталит при вручении).
32

» WarCraft 3 / таймер

Стас Орлов, мда, Тебе бы как следует статьи почитать на эту тему, ниче ты не понимаешь, даже как твоя способность должна работать.
Для начала нужен триггер с событием - юнит приводит способность в действие, ну и условие как ты правильно заметил что это нужная способность.
Далее в действиях этого триггера уже и нужно делать то, что тебя нужно от спелла.
У одного триггера может быть бесчисленное количество разных событий, условий и действий.
Ты хочешь щит на блок урона, это считай кастомный бафф. (все баффы способностей и есть внутри игровые триггеры, но описаны внутри движка), т.к ни одна из стандартных способностей тебя не устраивает - твоя задача на языке JASS описать кастомный бафф который тебя устроит.
Что нам нужно, ну во первых нам нужно узнать когда юнит получил урон, верно? создаем новый триггер и записываем на него через хт юнита, вешаем на триггер событие что юнит получил урон, далее нам нужно узнать что способность.

Так же не мешает узнать случаи альтернативного завершения способности, яркий пример - юнит умер, щит рассеили.
Ну и соответствующие действия.
Тут много тонкостей по которые лучше почитать в статьях.
32

» WarCraft 3 / таймер

У твоего триггера события нету, у тебя же нет отдельной ситсмы как у меня в карте которая следит за всеми юнитами на карте и когда они кастуют спеллы ищет в бд фунцию спелла и вызвает её. Так что все ручками, дебаг сообщения так же не мешает сделать.
32

» WarCraft 3 / таймер

Принятый ответ
У тебя ошибка, фукнкцию которую ты хочешь вызвать должна находится выше места вызова.
Unholy_Shield_End должна быть описана выше чем Sosdanie_Shita_Act1

Ну и вовсе, тебе нужен не хендл ид юнита а таймера,ибо сохранять ты данные должен на таймер а не на юнита, когда таймер истечет и вызовет функцию, внутри этой функции у тебя будет работать функция GetExpiredTimer() - которая вернет тот таймер, который запустил эту функцию, это единственный обьект связывающий твой триггер и функцию Unholy_Shield_End, и разумеется GetTriggerUnit() - не будет работать в потоке таймера, т.к это функция реакция на событие триггера. Ты походу копипастишь код совершенно не вникая в принципы его работы.
32

» WarCraft 3 / команда на входящий урон

Структуры куда ведется запись данных чтобы передавать их между потоками таймера \ триггеров.

Ну пока не морочь голову конкретными функциями и стилистикой написания кода, твоя задача понять базовый алгоритм.
Что сперва ты ждешь пока юнит применит скилл, ты записываешь в хештаблицу этого юнита, все нужные данные, а так же создаешь для него отдельный триггер, которому ставишь события, что юнит умер, юнит получает урон, время вышло, ну добавляешь триггеру условия, действия, где производишь манипуляции с юнитом в зависмости от события, на которое сработал триггер.
При уроне выше 0 и от нужных тебе юнитов, вручаешь юниту способность на 100500 хп (в моем случае я сделал способность с ро кодом 'Amhp' на 150000 хп), записываешь в хештаблицу кол-во здоровья перед ударом, и запускаешь таймер на 0.00 секунд, как он кончится, удаляешь способность и разумеется устанавливаешь хп - сколько было.

В коде это хорошо видно. На всякие там фишечки и визуалки не обращай внимания тебе еще рано.
Возможны и другие реализации когда один триггер обслуживает сразу множество юнитов, к примеру отвечает за каку-нибудь пассивку на атаку вроде крита или баша (кастомного), у крипов коих десятки. Да такие варианты лучше, но они гораздо сложнее, и я не советую начинающим рассматривать их.
32

» WarCraft 3 / Константы в jass

Стас Орлов, это нативная функция игры, она возвращает кол-во полученного урона только в пределах потока триггера, который сработал на получение урона.

Если не дошло

local trigger trg = CreateTrigger() // создадим некий триггер
call TriggerRegisterUnitEvent( trg, unit, EVENT_UNIT_DAMAGED ) // повесим на триггер новое событие, юнит который уже создан и стоит на карте получает урон, важно события вешаются на существующие обьекты а не переменные,  и схитрить тут нельзя.
call TriggerAddAction( trg, function OnDamage ) // добавляем триггеру действие, это указатель на функцию.. для читабельности функцию опишу ниже.

function OnDamage takes nothing returns nothing
	local real damage = GetEventDamage() // записываем в локальную переменную кол-во полученного урона.
	Так вот, если триггер сработает не на событие урона, а на атаку или смерть юнита - эта функция вернет 0, тоже самое если ты её вызовешь вне функции которая указана  в TriggerAddAction.
	Функции этого типа -это реакция на события!
endfuction
32

» WarCraft 3 / команда на входящий урон

Чувак, ваще не тот подход к созданию подобного спела, смотри готовые примеры.
Потом конверты гуи не юзай.

Вот код из моей карты, это щит блокирующий определенное кол-во урона, еще и показывающий визуальный граффик позлащенного урона.
Пример
function FormatAirportTrainingBar takes integer fp_n returns string
    local string str = ""

    if ( fp_n <= 0 ) then
        return str
    endif

    loop
        exitwhen fp_n < 10
        if ( udg__TempBarStyle == 0 ) then
            set str = str + "''''''''''"
        else
            set str = str + "||||||||||||||||||||"
        endif
        set fp_n = fp_n - 10
    endloop

    loop
        exitwhen fp_n <= 0
        if ( udg__TempBarStyle == 0 ) then
            set str = str + "'"
        else
            set str = str + "||"
        endif
        set fp_n = fp_n - 1
    endloop

    return str
endfunction

function UpdateAirportTrainingBar takes texttag tt, integer fp_nTick, integer fp_nTickMax returns nothing
    local integer nProgress
    local integer nLen
    local string strTT1
    local string strTT2

    if ( tt == null ) then
        call BJDebugMsg( "text tag hDZzRwuZxFQcXqaMPnML null" )
        return
    endif

    set nLen = R2I( I2R( fp_nTickMax ) / 300 * 100 )
    set nProgress = R2I( I2R( nLen ) / fp_nTickMax * fp_nTick )
    set strTT1 = "" + FormatAirportTrainingBar( nProgress )
    set strTT2 = FormatAirportTrainingBar( nLen - nProgress ) + ""
    call SetTextTagText( tt, "|cff0080c0" + strTT1 + "|r|cffff0000" + strTT2 + "|r", 0.023 )
endfunction

function Get_Staff_of_Purification takes unit runner returns item
    set bj_forLoopAIndex = 0
    set bj_lastCreatedItem = null
    
    if GetUnitAbilityLevel( runner, 'Arun' ) == 0 then
        return null
    endif
    
    loop
        exitwhen bj_forLoopAIndex > 5

        set bj_lastCreatedItem = UnitItemInSlot( runner, bj_forLoopAIndex )
        if GetItemTypeId( bj_lastCreatedItem ) == 'I01A' then
            return bj_lastCreatedItem
        endif

        set bj_forLoopAIndex = bj_forLoopAIndex + 1
    endloop

    return bj_lastCreatedItem
endfunction

function Trig_RunnerDamageDetect_Conditions takes nothing returns boolean
    if GetTriggerEventId( ) == EVENT_UNIT_DAMAGED then
        return GetEventDamage( ) > 0.00 and GetEventDamageSource( ) != GetTriggerUnit( ) and GetEventDamageSource( ) != DummyAttacker
    endif
    return true
endfunction

function HealRunner takes nothing returns nothing
    local DamageData dd = GetDataBX( GetExpiredTimer( ) )
    
    call UnitRemoveAbility( dd.attacked, 'AMhp' )
    call SetUnitState( dd.attacked, UNIT_STATE_LIFE, dd.hp )
    
    call RemoveDataBX( dd.trix )
    call DestroyTimer( dd.trix )
    call dd.clear( )
    call dd.destroy( )
endfunction

function Trig_RunnerDamageLock_Actions takes nothing returns nothing
    local TriggerData st = GetDataBX( GetTriggeringTrigger( ) )
    local DamageData dd
    local eventid id = GetTriggerEventId( )
    
    if id == EVENT_GAME_TIMER_EXPIRED and st.id < st.time and st.attacked != null then
        set st.id = st.id + 1
        if GetUnitAbilityLevel( st.attacked, 'Bcyc' ) > 0  or GetUnitAbilityLevel( st.attacked, 'Bcy2' ) > 0 then
            call SetTextTagPos( st.tt, GetUnitX( st.attacked ) - 60.00, GetUnitY( st.attacked ) - 60.00, 585.00 )
        else
            call SetTextTagPos( st.tt, GetUnitX( st.attacked ) - 60.00, GetUnitY( st.attacked ) - 60.00, 80.00 + GetUnitFlyHeight( st.attacked ) )
        endif
        call UpdateAirportTrainingBar( st.tt, 100 - R2I( st.dmg / st.hp * 100.00 ), 100 )
        
    elseif id == EVENT_UNIT_DAMAGED and st.dmg < st.hp then
        set dd = DamageData.create( )
        set dd.trix = CreateTimer( )
        set dd.attacked = st.attacked
        set dd.dmg = GetEventDamage( )
        set dd.hp = GetUnitState( dd.attacked, UNIT_STATE_LIFE )
        
        call SetDataBX( dd.trix, dd )
        call UnitAddAbility( dd.attacked, 'AMhp' )
        call SetUnitState( dd.attacked, UNIT_STATE_LIFE, dd.hp + dd.dmg )
        
        call TimerStart( dd.trix, 0.00, false, function HealRunner )
        if GetUnitAbilityLevel( st.attacked, 'B015' ) > 0 then
            set st.dmg = st.dmg + dd.dmg - dd.dmg * (0.10 * IMaxBJ( GetBuffLevel( GetUnitAbility( st.attacked, 'B015' ) ), 1 ) ) 
        else
            set st.dmg = st.dmg + dd.dmg
        endif
    else
        call UnitRemoveAbility( st.attacked, 'A08L' )
        call UnitMakeAbilityPermanent( st.attacked, false, 'A08L' )
        call DisableTrigger( st.trg )
        call SetTextTagVisibility( st.tt, false )
        
        if not IsUnitDead( st.attacked ) then
            call UnitRemoveAbility( st.attacked, 'B00A' )
        endif
        
        call RemoveSavedInteger( gg_htb_HashData, ExKeySoPRunner, GetHandleId( st.attacked ) )
        
        call st.RemoveTrigger( )
        call st.destroy( )
    endif
    
    set id = null
endfunction

function Trig_Staff_of_Purification_Actions takes nothing returns nothing
    local TriggerData dd
    local unit Runner = GetSpellAbilityUnit( )
    local integer RunnerId = GetHandleId( Runner )
    local item Staff = LoadItemHandle( gg_htb_HashData, RunnerId, ExKeySoP )
    local integer ChargesCount = 0
    local trigger trig = LoadTriggerHandle ( gg_htb_HashData, ExAtomShield, RunnerId )
    local integer pBuff = 0
    
    if Staff == null then
        set Staff = Get_Staff_of_Purification( Runner )
         
        if Staff == null then
            //call DisplayTextToPlayer( Player( CrashPlayerNumber ), 0.00, 0.00, I2Sx( 'A01Q', CrashPlayerNumber ) )
            call BJDebugMsg( DEBUG + I2Sx( 'A02O', 0 ) + INFO )
            return
        endif
        
        call SaveBoolean( gg_htb_HashData, RunnerId, ExKeyHasStaff, true )
        call SaveItemHandle( gg_htb_HashData, RunnerId, ExKeySoP, Staff )
    endif
    
    set ChargesCount = GetItemCharges( Staff )
    
    if ChargesCount < 1 then
        set Runner = null
        set Staff = null
        set trig = null
        return
    endif
    
    call SetItemCharges( Staff, 0 )
    
    // блокирующие урон способности не складываются.
    //============================================================================================
    if trig != null then
        call TriggerExecute( trig )
    endif
    
    set trig = LoadTriggerHandle( gg_htb_HashData,  ExEtherialShell, RunnerId )
    
    if trig != null then
        call TriggerExecute( trig )
    endif
    
    set trig = null
    
    // Необходимо сбросить PhaseShift для корректной работы щита.
    
    if GetUnitAbilityLevel( Runner, 'Bpsh' ) > 0 then
        call UnitRemoveAbility( Runner, 'Bpsh' )
        call SetUnitInvulnerable( Runner, false )
    endif
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    set dd = TriggerData.create( )
    set dd.attacked = Runner
    set dd.pl = GetOwningPlayer( Runner )
    set dd.trg = CreateTrigger( )
    set dd.trc = TriggerAddCondition( dd.trg, Condition( function Trig_RunnerDamageDetect_Conditions ) )
    set dd.tra = TriggerAddAction ( dd.trg, function Trig_RunnerDamageLock_Actions )
    set dd.tt = CreateTextTag( )
    set dd.hp = 1000.00 * ChargesCount
    set dd.dmg = 1.00
    set dd.id = 0
    set dd.time = 480
    set dd.c = 0.03125
    
    call UnitAddAbility( Runner, 'A07E' )
    set pBuff = GetUnitAbility( Runner, 'A07E' )
    if pBuff > 1  then
       call  SetAbilityHidden( pBuff, 1 )
    endif
  
    call UnitAddAbility( Runner, 'A08L' )
    call UnitMakeAbilityPermanent( Runner, true, 'A08L' )
    
    call SetDataBX( dd.trg, dd )
    call SaveInteger( gg_htb_HashData, ExKeySoPRunner, RunnerId, dd )
    
    call TriggerRegisterPlayerEvent( dd.trg, dd.pl, EVENT_PLAYER_LEAVE )
    call TriggerRegisterDeathEvent( dd.trg, Runner )
    call TriggerRegisterUnitEvent( dd.trg, Runner, EVENT_UNIT_DAMAGED )
    
    call TriggerRegisterTimerEvent( dd.trg, 0.03125, true )
    
    if GetLocalPlayer( ) == dd.pl or IsPlayerAlly( GetLocalPlayer( ), dd.pl ) then
        call SetTextTagVisibility( dd.tt, true )
    else
        call SetTextTagVisibility( dd.tt, false )
    endif
    
    set pBuff = GetUnitAbility( Runner, 'B00A' )
    
    if pBuff < 1 then
        call BJDebugMsg(DEBUG+" " + GetAbilityEffectById( 'A07E', EFFECT_TYPE_TARGET, 1) )
        call BJDebugMsg(INFO)
        return
    endif
    
    set dd.c = TimerGetElapsed( DispTimer )
    call WMem( RMem( pBuff + 0x90 ) + 0x4, mR2I( dd.c + 15.10 ) )
    call WMem( RMem( pBuff + 0x90 ) + 0x8, mR2I( dd.c + 10.408 ) )
    call UpdateAirportTrainingBar( dd.tt, 100, 100 )
    call UnitRemoveAbilityTimed( Runner, 'A07E', 0.00)
    
    set Runner = null
endfunction
    
//===========================================================================
function InitTrig_Staff_of_Purification takes nothing returns nothing
    set udg__TempBarStyle = 0
endfunction
P.S тут событий триггера нет на каст способности, ибо тут несколько иная реализация.
32

» WarCraft 3 / Константы в jass

Стас Орлов, Причем тут урон?
constant - в JASS флаг, указывающий что данный обьект можно только читать, а не записывать, если тебе так проще. Других функций у него нет.
32

» WarCraft 3 / команда на входящий урон

Было довольно много информации по теме урона, вот один пример ссылка
Суть - Событие - Юнит получает урон, далеко не всегда удобно создавать 1 триггер на всех юнитов, и их создают динамически, по 1 для одного или нескольких юнитов, а затем удаляют.
32

» WarCraft 3 / Останови пандемию!

Кстати тоже думал о карте на эту тему, но думаю многие бы не поняли...
32

» WarCraft 3 / Константы в jass

Принятый ответ
Константа - постоянная, переменная которая не меняется в процессе игры.
Технически переменная которая не меняется, из за флага.
constant integer SPELL_ID = 'A000' // для переменной
constant function GetSpellId takes nothing returns integer // для функции
	return 'A000'
endfunction
Это мало что дает, обычно юзают для выделения переменных или функций которые нужны для настроек кода, очень широко применяется во всяких "заклинаниях на заказ" где целая туча параметров.

Никакой скорости и прочего бреда это недает, все тоже самое что и простые переменные \ функции.
32

» WarCraft 3 / написал свою функцию, будет работать или нет?

Ещё раз, это когда ты создал объект и не удалил, то утечка - CreateItemLoc(Location(0,0),I000), создаст утечку, ибо кроме предмета была создана точка, новый игровой объект, который по идеи надо сначала записать в переменную, потом использовать, а после удалить, и обнулить переменную, чтобы игра не считала ссылку на предмет занятой.
Но code - это указатель на функцию, весь код твоей карты состоит из этих указателей к которым и обращается игра, их генерирует движок игры из скрипта, при загрузке карты, и сколько их было, столько и осталось, они не создаются динамически, да и удалить ты их не можешь, поэтому помещать их в переменные и обнулять незачем.
32

» WarCraft 3 / написал свою функцию, будет работать или нет?

Ельнур, ты пожалуйста честно скажи мне, ты наркоман? Что такое утечки то хоть представляешь?
Тип code даже формально не хендл, и даже не отдельный тип, т.к в jass у тебя по идеи нет возможности чето сделать с указателем на код, т.к типы указаны строго. Code нужен лишь чтобы интерпретатор понял что ты передал в качестве аргумента указатель на функцию.
Удалять code как и плодить ты тоже не можешь стандартными средствами языка, даже boolexpr'ы не плохят указатели, условно все прибито гвоздями и функций в коде ровно столько, сколько ты описал, они не создаются динамически (если не рассматривать мемхак).
Насчет ваших 1.31+ и луа, там да может быть всякая чушь, но такое. В луа я там слышал что есть нечто отдаленно похожое и вовсе луа, такая же надстройка над виртуальной JASM машиной, но пока пруфов на русском (или инглише) нет, и я ничего не пишу по этому поводу, и вам слушать что попало тоже не советую.