21

» WarCraft 3 / Фаталит карта

Готовые системы вешают событие на всех юнитов, а я сделал так, чтобы вешало лишь на тех, на кого мне нужно
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

» WarCraft 3 / Фаталит карта

    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
на одном юните не может быть более одного повешанного события.
Загруженные файлы
21

» WarCraft 3 / Фаталит карта

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

» WarCraft 3 / Фаталит карта

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
Чёрт,, почему это так гениально.?
21

» WarCraft 3 / Поиск элемента БД

avuremybe, мы конечно понимаем, что говоря бесконечность, Вы имели ввиду большое число. Но каким может быть это большое число? Сколько времени уходит на создание одного предмета (история предмета, характеристики, описание, триггерные способности у предмета, сама идея для предмета)? Мне кажется, довольно таки много..)))
А теперь представьте, что Вы сделали 1000 предметов. Вы когда нибудь видели карту с 1000 предметов? В той же доте (мне кажется, эта карта лидер по количеству предметов) около 100 предметов, а у Вас будет аж в десять раз больше, Карл!
Думаю, что, даже если Вы поставите лимит в 128 512 предметов, этого будет более чем достаточно..))
21

» WarCraft 3 / Фаталит карта

Всем спасибо за ответы, проблему я уже решил, дело было не в данной функции.
У меня была система, которая позволяла добавить событие "любой юнит атакован".
Также, был триггер, событие которого было как раз "любой юнит атакован".
В этом триггере триггерно наносился урон, который, естественно запускал этот триггер снова, и снова, и снова. Эдакая цепная реакция получалась.
Это и приводило к фаталу, хотя не понятно, почему фаталит... Цепная реакция должна сама ведь прекратиться, когда юнит умрёт. То есть, юниту наносится урон, потом еще, и еще, пока юнит не умрёт.
Или варик крашится, если триггер сам себя запускает без задержек по кд?
21

» WarCraft 3 / Скрыть индикатор загрузки

Это вроде нельзя реализовать официальным способом. Можно только с помощью бага какого-то.
21

» WarCraft 3 / Поиск элемента БД

Ige, а если так:
	function HaveItem takes unit shop, integer itemid returns boolean
		return HaveSavedInteger(ht, GetUnitUserData(shop), itemid)
	endfunction

	function ShopAddItem takes unit shop, integer itemid returns nothing
		if not HaveItem(shop, itemid) then
			//...
			call SaveInteger(ht, GetUnitUserData(shop), itemid, itemid)
			//...
		endif
	endfunction
21

» WarCraft 3 / Процентный урон

Думаю, лучше использовать GetUnitState(), а не GetWidgetLife(), потому что второе возвращает лишь текущее ХП, а процентный урон может быть как и от текущего ХП, так и от максимального ХП.
21

» WarCraft 3 / Поиск элемента БД

HaveSavedInteger( hashtable, parentKey, childKey )
С помощью данной функции Вы можете узнать, хранится ли равкод юнита в Вашей хеш-таблице.
21

» WarCraft 3 / Как добавляются нативки?

16GB, ну, это понятно, что ее нужно объявить, я не пойму, как это начинает работать без тела самой функции. Ведь, если я напишу,
native IsTerrainWalkable takes real x, real y returns boolean
это же не будет работать.
21

» WarCraft 3 / Иногда хеш таблица запаздывает???

немного не по теме, но что если Хеш-таблицу инициализировать сразу же после объявления?
	globals
		constant hashtable HASHTABLE = InitHashtable( )
	endglobals
21

» WarCraft 3 / Двухсторонний телепорт

Maniac_91, я думаю можно без отключения триггера, после телепорта даешь юниту абилку пустышку, и убираешь ее, когда юнит покидает область телепорта. Таким образом, чтобы обратно вернуться, юниту необходимо после телепорта выйти из области , а затем снова войти в неё. А если отключить триггер, не смогут телепортироваться все юниты.
21

» WarCraft 3 / Искусственный интеллект

А как можно примерно реализовать самообучение? Хотя бы супер простой пример.
21

» WarCraft 3 / Рандом Варкрафта и Абилки с шансом

Пока что-то мне псевдорандом не очеьн нравится, посмотреть бы как на него в действии, оставим его на попозже
Ну так все способности из Warcraft 3 имеющие шанс срабатывания и являются псевдорандомными)
21

» WarCraft 3 / Рандом Варкрафта и Абилки с шансом

Proshel_Doty,
Jinada Bounty Hunter'a из Dota имеет перезарядку, хоть и является пассивной способностью.
21

» WarCraft 3 / Рандом Варкрафта и Абилки с шансом

Как он действует? Как его сделать
Первый удар - 10%
Второй удар - 20%
Третий удар - 30%
Четвёртый удар - 40% и т.д.
Шанс срабатывания растёт с каждым ударом, а в случае прока возвращается обратно на свои изначальные значения.
21

» WarCraft 3 / Передача данных в другую функцию для группы

Понимаешь, была бы какая-нибудь задержка, и в отрывке времени сработало бы другое событие, твой GetTriggerUnit может быть другого юнита давал бы.
Мне кажется как раз переменные могут перезаписаться, если будет задержка. А GetTriggerUnit() привязан к потоку и перезаписаться не может, если я правильно всё понял.
21

» WarCraft 3 / Можно ли сделать способность у героя изначальной?

Создайте обычную не-геройскую способность, а затем дайте его герою через редактор объектов так же, как это делается и с обычными юнитами.
21

» WarCraft 3 / GetTriggerPlayer( )

Extremator:
всё равно нужно получить владельца юнита-инициатора
Я не понял, как понять "всё равно нужно" ? :-)