21

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

quq_CCCP, quq_CCCP, ну так я же хочу, чтобы не было трупа. а TimedLife просто убивает юнита, в моём случае, он попытается еще раз убить юнита, который уже мертв.
21

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

DracoL1ch, причина удаления юнитов у меня странная, - мне не нравится трупы юнитов, которые везде валяются. Если юнитов нельзя удалять, то как мне спрятать юнита? Если спрятать юнита функцией ShowUnit(), удалится ли юнит после полного разложения его трупа? или же это функция может как-то воспрепятствовать удалению юнита движком игры?
21

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

DracoL1ch, 100% рабочего способа вызвать фатал у меня действительно нету. Но я нашел участок кода, при отключении которого, карта перестает критовать. Это был обычный триггер, который удалял юнита после его смерти, но сам этот триггер не критует, он начинает критовать только если герой прокачивает данный спелл.
spell
scope Omnislash



    globals

//      Ability rawcode.
        private    constant    integer       SPELL_ID            =    'A00K'

//      Dummy image rawcode.
        private    constant    integer       DUMMY_ID            =    'o000'

//      Timer's period.
        private    constant    real          FPS                 =    0.03125

//      Times between slashes.
        private    constant    real          BASE_ATTACK_TIME    =    0.375

        private    constant    real          ENEMY_SEARCH_RADIUS    =    600.0

//      Blademaster's attack range.
        private    constant    real          ATTACK_RANGE        =    100.0

//      Effect on dealing damage.
        private    constant    string        EFFECT_01           =    "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl"

//      Effect on weapon.
        private    constant    string        EFFECT_02           =    "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl"

//      Is damage attack?
        private    constant    boolean       ATTACK_FLAG         =    true

//      Is damage ranged?
        private    constant    boolean       RANGED_FLAG         =    false

//      Attack type.
        private    constant    attacktype    ATTACK_TYPE         =    ATTACK_TYPE_HERO

//      Damage type.
        private    constant    damagetype    DAMAGE_TYPE         =    DAMAGE_TYPE_NORMAL

//      Weapon type.
        private    constant    weapontype    WEAPON_TYPE         =    WEAPON_TYPE_METAL_HEAVY_SLICE

    endglobals



    private function GetUnitAttackDamage takes unit blademaster returns integer
        local  integer  agility  =  GetHeroAgi( blademaster, true )
        local  integer  sides    =  3
        local  integer  dice     =  3

        return GetRandomInt( ( agility + dice ), ( agility + dice * sides ) )
    endfunction



    private function GetAnimationIndex takes nothing returns integer
        local integer i = GetRandomInt( 0, 2 )

        if ( i == 0 ) then
            return 2

        elseif ( i == 1 ) then
            return 3
        endif

        return 8
    endfunction



    struct omnislashdummy
        private        unit     dummy
        private        integer  alpha
        private        effect   fx

        private        thistype prev
        private        thistype next

        private static timer    period = CreateTimer( )



        private method destroy takes nothing returns nothing
            call DestroyEffect( this.fx )
            call RemoveUnit( this.dummy )

            set this.fx        = null
            set this.dummy     = null

            set this.prev.next = this.next
            set this.next.prev = this.prev

            if ( thistype(0).next == 0 ) then
                call PauseTimer( period )
            endif

            call thistype.deallocate( this )
        endmethod



        private static method iterate takes nothing returns nothing
            local thistype this    = thistype(0).next

            loop
                exitwhen ( this == 0 )

                if ( this.alpha <= 0 ) then
                   call this.destroy( )
                else
                    set this.alpha = this.alpha - 8
                    call SetUnitVertexColor( this.dummy, 255, 255, 255, IMaxBJ( this.alpha, 0 ) )
                endif

                set this = this.next
            endloop
        endmethod



        static method create takes unit target, unit caster returns thistype
            local thistype this = thistype.allocate( )
            local real     x    = GetUnitX( target ) + GetRandomReal( -ATTACK_RANGE, ATTACK_RANGE )
            local real     y    = GetUnitY( target ) + GetRandomReal( -ATTACK_RANGE, ATTACK_RANGE )
            local real     f    = bj_RADTODEG * Atan2(GetUnitY( target ) - y , GetUnitX( target ) - x )

            set this.next = thistype(0)
            set this.prev = thistype(0).prev
            set this.next.prev = this
            set this.prev.next = this

            set this.dummy = CreateUnit( GetOwningPlayer( caster ), DUMMY_ID, x, y, f )
            set this.fx    = AddSpecialEffectTarget( EFFECT_02, this.dummy, "weapon" )
            set this.alpha = 255

            call PauseUnit( this.dummy, true )
            call UnitAddAbility( this.dummy, 'Amrf' )
            call UnitRemoveAbility( this.dummy, 'Amrf' )
            call SetUnitFlyHeight( this.dummy, GetUnitFlyHeight( target ), 0.0 )
//          call UnitAddAbility( this.dummy, 'Aloc' )
//          call SetUnitInvulnerable( this.dummy, true )
            call SetUnitPathing( this.dummy, false )
            call SetUnitAnimationByIndex( this.dummy, GetAnimationIndex( ) )

            if ( this.prev == 0 ) then
                call TimerStart( period, FPS, true, function thistype.iterate )
            endif

            return this
        endmethod



    endstruct



    struct omnislash
        private        unit     caster
        private        unit     target
        private        effect   fx
        private        integer  slash
        private        real     bat
        private        real     range
        private        real     casterX
        private        real     casterY
        private        real     targetX
        private        real     targetY

        private        thistype prev
        private        thistype next

        private static group    group   = CreateGroup( )
        private static timer    period  = CreateTimer( )
        private static trigger  trigger = CreateTrigger( )



        private method destroy takes nothing returns nothing
            call DestroyEffect( this.fx )
            call PauseUnit( this.caster, false )
//          call SetUnitInvulnerable( this.caster, false )
            call SetUnitPathing( this.caster, true )
            call SetUnitTimeScale( this.caster, 100 * 0.01)
            call SetUnitVertexColor( this.caster, 255, 255, 255, 255 )
            call SetUnitFlyHeight( this.caster, 0.0, 0.0 )

            set this.caster = null
            set this.target = null
            set this.fx     = null

            set this.prev.next = this.next
            set this.next.prev = this.prev

            if ( thistype(0).next == 0 ) then
                call PauseTimer( period )
            endif

            call thistype.deallocate( this )
        endmethod



        private static method getParabolaZ takes real maxHeight, real maxRange, real currentRange returns real
            return ( 4 * maxHeight / maxRange ) * ( maxRange - currentRange ) * ( currentRange / maxRange )
        endmethod



        private method getRandomUnitFromGroup takes nothing returns unit
            call GroupEnumUnitsInRange( thistype.group, this.casterX, this.casterY, ENEMY_SEARCH_RADIUS, null )

            loop
                set bj_groupRandomConsidered  = 0
                set bj_groupRandomCurrentPick = null
                call ForGroup( thistype.group, function GroupPickRandomUnitEnum )
                exitwhen ( bj_groupRandomCurrentPick == null ) or ( IsUnitEnemy( bj_groupRandomCurrentPick, GetOwningPlayer( this.caster ) ) and IsUnitAlive( bj_groupRandomCurrentPick ) and ( not IsUnitType( bj_groupRandomCurrentPick, UNIT_TYPE_STRUCTURE ) ) )
                call GroupRemoveUnit( thistype.group, bj_groupRandomCurrentPick )
            endloop

            call GroupClear( thistype.group )
            return bj_groupRandomCurrentPick
        endmethod



        private static method iterate takes nothing returns nothing
            local thistype this    = thistype(0).next

            local real     range

            loop
                exitwhen ( this == 0 )

                if ( this.slash > 0 ) and IsUnitAlive( this.caster ) then
                    call SetUnitFacing( this.caster, ( bj_RADTODEG * Atan2( this.targetY - this.casterY, this.targetX - this.casterX ) ) )

                    if ( this.bat <= 0.0 ) then
                        set this.targetX = GetUnitX( this.target )
                        set this.targetY = GetUnitY( this.target )
                        set range = SquareRoot( ( this.targetX - this.casterX ) * ( this.targetX - this.casterX ) + ( this.targetY - this.casterY ) * ( this.targetY - this.casterY ) )

                        if ( range <= 120 ) then
                            set this.casterX = this.targetX + GetRandomReal( -ATTACK_RANGE, ATTACK_RANGE )
                            set this.casterY = this.targetY + GetRandomReal( -ATTACK_RANGE, ATTACK_RANGE )
                            call SetUnitX( this.caster, this.casterX )
                            call SetUnitY( this.caster, this.casterY )
                            call SetUnitFlyHeight( this.caster, 0.0, 0.0 )
                            call omnislashdummy.create( this.target, this.caster )
                            call SetUnitAnimationByIndex( this.caster, GetAnimationIndex( ) )
                            call DestroyEffect( AddSpecialEffectTarget( EFFECT_01, this.target, "origin" ) )
                            call UnitDamageTarget( this.caster, this.target, ( GetHeroAgi( this.caster, true ) + 25.0 ), ATTACK_FLAG, RANGED_FLAG, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE )
                            set this.bat = BASE_ATTACK_TIME

                            set this.target = this.getRandomUnitFromGroup( )
                            if ( this.target != null ) then
                                set this.slash    =  ( this.slash - 1 )
                                set this.targetX  =  GetUnitX( this.target )
                                set this.targetY  =  GetUnitY( this.target )
                                set this.range    =  SquareRoot( ( this.targetX - this.casterX ) * ( this.targetX - this.casterX ) + ( this.targetY - this.casterY ) * ( this.targetY - this.casterY ) )

                            else
                                call this.destroy( )
                            endif

                        else
                            set this.casterX = this.casterX + 60.0 * ( ( this.targetX - this.casterX ) / range )
                            set this.casterY = this.casterY + 60.0 * ( ( this.targetY - this.casterY ) / range )
                            call SetUnitX( this.caster, this.casterX )
                            call SetUnitY( this.caster, this.casterY )
                            call SetUnitFlyHeight( this.caster, thistype.getParabolaZ( 180.0, this.range, ( this.range - range ) ), 0.0 )
                        endif

                    else
                        set this.bat = this.bat - FPS
                    endif

                else
                    call this.destroy( )
                endif

                set this = this.next
            endloop
        endmethod



        private static method actions takes nothing returns nothing
            local eventid  id          = GetTriggerEventId( )
            local thistype this
            local unit     blademaster
            local unit     attacker

            if ( id  == EVENT_PLAYER_UNIT_ATTACKED ) then
                set blademaster = GetTriggerUnit( )
                set attacker    = GetAttacker( )

                call omnislashdummy.create( attacker, blademaster )
                call UnitDamageTarget( blademaster, attacker, GetUnitAttackDamage( blademaster ), ATTACK_FLAG, RANGED_FLAG, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE )

                set blademaster = null
                set attacker    = null

            elseif ( id == EVENT_PLAYER_UNIT_SPELL_EFFECT ) then
                set this = thistype.allocate( )

                set this.next      = thistype(0)
                set this.prev      = thistype(0).prev
                set this.next.prev = this
                set this.prev.next = this

                set this.caster    = GetSpellAbilityUnit( )
                set this.casterX   = GetUnitX( this.caster )
                set this.casterY   = GetUnitY( this.caster )
                set this.target    = GetSpellTargetUnit( )
                set this.targetX   = GetUnitX( this.target )
                set this.targetY   = GetUnitY( this.target )
                set this.fx        = AddSpecialEffectTarget( EFFECT_02, this.caster, "weapon" )
                set this.slash     = GetUnitAbilityLevel( this.caster, SPELL_ID ) * 2 + 10
                set this.bat       = 0.0
                set this.range     = SquareRoot( ( this.targetX - this.casterX ) * ( this.targetX - this.casterX ) + ( this.targetY - this.casterY ) * ( this.targetY - this.casterY ) )

                call UnitAddAbility( this.caster, 'Amrf' )
                call UnitRemoveAbility( this.caster, 'Amrf' )
                call PauseUnit( this.caster, true )
//              call SetUnitInvulnerable( this.caster, true )
                call SetUnitPathing( this.caster, false )
                call SetUnitTimeScale( this.caster, 250 * 0.01 )
                call SetUnitVertexColor( this.caster, 255, 255, 255, 100 )

                if ( this.prev == 0 ) then
                    call TimerStart( period, FPS, true, function thistype.iterate )
                endif
            endif

            set id = null
        endmethod



        private static method conditions takes nothing returns boolean
            local eventid eventId     = GetTriggerEventId( )
            local unit    blademaster = GetTriggerUnit( )
            local integer chance      = GetUnitAbilityLevel( blademaster, SPELL_ID ) * 6 + 10
            local boolean b           = false

            if ( eventId == EVENT_PLAYER_UNIT_ATTACKED ) then
                set b = ( GetUnitAbilityLevel( blademaster, SPELL_ID ) > 0 ) and ( GetRandomReal( 0.0, 100.0 ) <= chance )

            elseif ( eventId == EVENT_PLAYER_UNIT_SPELL_EFFECT ) then
                set b = ( GetSpellAbilityId( ) == SPELL_ID )
            endif

            set eventId     = null
            set blademaster = null

            return b
        endmethod



        private static method onInit takes nothing returns nothing
            call PreloadAbility( SPELL_ID )
            call PreloadUnit( DUMMY_ID )
            call PreloadEffect( EFFECT_01 )

            call TriggerRegisterAnyUnitEventBJ( thistype.trigger, EVENT_PLAYER_UNIT_ATTACKED )
            call TriggerRegisterAnyUnitEventBJ( thistype.trigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )

            call TriggerAddCondition( thistype.trigger, Condition( function thistype.conditions ) )
            call TriggerAddAction( thistype.trigger, function thistype.actions )
        endmethod



    endstruct



endscope
также, если удалить этот триггер, удаляющий юнитов после смерти. А вместо него в редакторе констант выставить минимальные значения разложения трупа, то карта снова начинает критовать.

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

P.S.: это Omnislash Juggernaut'a из доты, правда немного изменённый. Также, у данной способности есть пассивная составляющая - каждый раз, когда героя атакуют, имеется какой-то шанс, контратаковать атакующего (создается даммик, который проигрывает анимацию атаки и врагу наносится урон).
21

» WarCraft 3 / Высота Z

x = x + move_cord * Cos( a ) * Sin( t )
y = y + move_cord * Sin( a ) * Sin( t )
z = z + move_cord * Cos( t )
21

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

quq_CCCP, мемхак убрал с карты, а использовал героя только для того, чтобы не создавать новую боевую единицу, захламляя редактор объектов. Когда в редакторе становится много объектов становится сложно разбираться во всем этом. Ну и собственно, мой первый вопрос, мог ли этот даммик быть причиной фатала?
21

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

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

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

quq_CCCP, ну у даммика изначально нету москитов, они добавляются после создания даммика. или это не важно? я подумал, что фатал успевает призойти между созданием дамми и добавлением москитов
21

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

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

» WarCraft 3 / Есть ли ограничение по числу триггеров, областей или переменных?

Возможно не совсем по теме, но хотел бы спросить: есть ли ограничение на самих триггеров (без инициализации). То есть куча триггеров, но в них код написан на JASS/vJASS и инициализация разделена на потоки (через library).
21

» WarCraft 3 / PreloadAbility( integer )

PT153, зависит от их максимального уровня. Возможно Вам понадобится подгружать не 100500, а уже 50250 способностей.
21

» WarCraft 3 / constant function

quq_CCCP, но ведь Вы написали о константных переменных, значение которых защищены от изменения, а от чего же защищены константные функции?
Если верить моим исследованиям, то они защищены от неконстантных глобальных переменных и от неконстантных функций, которые могут находиться в них, но зачем?
21

» WarCraft 3 / constant function

А юнит может оказаться как живым, так и не живым.
почему тогда функция IsUnitAlive( ) работает исправно:
сonstant function IsUnitAlive takes unit whichUnit returns boolean
	return not ( IsUnitType( whichUnit, UNIT_TYPE_DEAD ) or ( GetUnitTypeId( whichUnit ) == 0 ) )
endfunction
21

» WarCraft 3 / структура и перебирание данных в ней

quq_CCCP, благодарю, но всё же хотелось бы именно с thistype.next, thistype.prev.
кажется, я сделаль:
struct data
        static timer    period = CreateTimer( )
               thistype prev
               thistype next

               unit     u
               integer  a

        method destroy takes nothing returns nothing
            set this.prev.next = this.next
            set this.next.prev = this.prev

            if ( thistype(0).next == 0 ) then
                call PauseTimer( period )
            endif

            call thistype.deallocate( this )
        endmethod

        static method iterate takes nothing returns nothing
            local thistype this = thistype( 0 ).next

            loop
                exitwhen ( this == 0 )

				set this.a = this.a + 1
				call SetUnitVortexColor( this.u, 255, 255, 255, this.a )

                if ( this.a > 255 ) then
                    call this.destroy( )
                endif

                set this = this.next
            endloop
        endmethod

        static method createUnit takes nothing returns thistype
            local thistype this = thistype.allocate( )

            set this.next = 0
            set this.prev = thistype(0).prev
            set this.next.prev = this
            set this.prev.next = this

			set this.u = CreateUnit(...)
			set this.a = 0
			call SetUnitVortexColor( this.u, 255, 255, 255, this.a )
            
            if ( this.prev == 0 ) then
                call TimerStart( period, 0.03125, true, function thistype.iterate )
            endif

            return this
        endmethod

    endstruct
21

» WarCraft 3 / структура и перебирание данных в ней

Clamp, Ваш код, к сожалению, я совсем не понял. Мне бы простой код, такой, какой я сам выложил наверху.
21

» WarCraft 3 / структура и перебирание данных в ней

quq_CCCP, да, это я сам написал, но она не работает, потому что я не знаю как написать правильно используя next, prev
21

» WarCraft 3 / constant function

Clamp:
DracoL1ch:
а ты пробовал? логика говорит, что constant функция всегда возвращает константу и не может работать с параметрами :)
Я не программист и не силён в терминологии. Но вышеуказанный скрин, мне кажется, говорит, что константная функция может работать с параметрами.
21

» WarCraft 3 / constant function

Clamp, если я правильно понял, то почему это работает?
code
constant function sum takes integer a , integer b returns integer
    return a + b
endfunction

function test takes nothing returns nothing
    call BJDebugMsg( I2S( sum (1, 1 ) ))
    call BJDebugMsg( I2S( sum (2, 2 ) ))
endfunction

//===========================================================================
function InitTrig_test takes nothing returns nothing
    set gg_trg_test = CreateTrigger(  )
    call TriggerRegisterTimerEventSingle( gg_trg_test, 1.00 )
    call TriggerAddAction( gg_trg_test, function test )
endfunction
screen
Ещё можно предварительно пробовать, а не задавать превентивные вопросы.
Я спросил быстрее это или нет, а Вы отвечаете, что не работает, хотя в работоспособности я и не сомневался.
Загруженные файлы
21

» WarCraft 3 / constant function

Hate, Вы акцентируете внимание совсем на другое. Это понятно, что лучше вставить код из самой функции, вместо его вызова (как Вы и написали).
Я же хотел обратить Ваше внимание не на это, a на саму функцию IsUnitAlive( ) и на ускорение кода, если сделать её константной.
То есть Ваш ответ должен быть:
  • ускорения не будет совсем
  • ...
  • ускорение будет, но очень маленькое, что даже можно это не учитывать
  • ...
  • ускорение будет достаточно хорошим и функцию стоит сделать константной.
21

» WarCraft 3 / constant function

Hate:
вас должно заботить не то, быстрее ли такая функция или медленнее, а оптимизация узких мест, вот где важна скорость выполнения. не в ту сторону смотрите
Я про это и думал. Ведь можно сделать функцию константной, которая вызывается таймером с малым периодом.
code
	function IsUnitAlive takes unit whichUnit returns boolean
		return not ( IsUnitType( whichUnit, UNIT_TYPE_DEAD ) or ( GetUnitTypeId( whichUnit ) == 0 ) )
	endfunction
	
	function TimerCallback takes nothing returns nothing
	  	...
		if ( IsUnitAlive( unit ) ) then
			...
		endif
		...
	endfunction

	function Start takes nothing returns nothing
		call TimerStart( CreateTimer( ), 0.03125, true, function TimerCallback )
	endfunction 
Вот что я имел ввиду.
21

» WarCraft 3 / PreloadAbility( integer )

quq_CCCP, куда должен сохранится данный файл? Здесь ничего не сохранилось. Или файл не сюда сохраняется?
	...\Program Files (x86)\WarCraft 3\Save\
21

» WarCraft 3 / PreloadAbility( integer )

quq_CCCP, не совсем понимаю.
	function PreloadAbility takes integer id returns boolean
		return UnitAddAbility( unitPreloader, id )
	endfunction
А что такое pld скрипты, google ничего не выдал..
а что насчёт call SetUnitInvulnerable( ... ), call UnitAddAbility( unit, 'Avul' )