Добавлен , опубликован
Способ реализации:
Версия Warcraft:

Демонстрация

С помощью ESC можно закрыть преждевременно загадку. Стрелками влево/вправо вы перемещаете отмычку с одного штифта на другой, с помощью клавиши вверх вы поднимаете отмычку, ударяя об штифт, который нужно грамотно зафиксировать пробелом в самом вверху. После проделывания подобных манипуляций с каждым штифтом - сундук открывается и оттуда вылезает моё разбитое подобие сердца приносящее лишь боль агонию и страдания всему живому и неживому лучше бы сдох бьвапыждщорпдчит

+ Мультиплеерное
+ Игрок не может открыть головоломки других сундуков, пока решает текущую (сделано в случае управления множеством юнитов на одного игрока)
+ Игрок не может открыть головоломку сундука, если её уже кто-то решает
+ Открытый сундук нельзя решить повторно
+ Если юнит, открывший головоломку сундука, будет перемещён на достаточное расстояние или умрёт - головоломка закроется для игрока
+ Отличное дополнение для карт жанра РПГ
+ Уже зафиксированные штифты сохраняют своё положение

предыстория

Эта головоломка была горекриво сделана на мемхаке для новой версии карты [Конкурс становления героев] Crusader, которую мы с Dragonlor так и не закинули, ибо работы там дочерта, а возвращаться к этому проекту больше не хотим. Я решил доработать эту головоломку, благодаря UjAPI удалось сделать её мультиплеерной и выкатить на свет в принципе

Инструкция по импорту

  • Работает исключительно на UjAPI, поэтому вам необходимо установить лаунчер

Скопировать папку Initialization и закинуть в свою карту вместе со всем импортом, создав соответствующие переменные звука
Триггер Sound нужен только для одного позиционированного звука открывания сундука и взят с уже существующей наработки 3д звук, оно опционально и можно удалять, не забыв стереть 238 строку и requires SoundLib в самом вверху триггера Chest
В триггере Chest нужно указать лишь равкоды сундука на 379 и 330 строках, всё остальное требует минимальных знаний джасса (это, к примеру, если есть необходимость изменить масштабирование всех фреймов и их позиционирование). На 240 строке создаётся демонстративный предмет при открывании сундука. Вы можете заменить эту строку вызовом триггера call TriggerEvaluate( gg_trg_название ) и делать нужные вещи уже на гуи, перед этим можно присвоить переменную Target[i] (сундук) своей гуишной для необходимых действий (Caster[i] - тот, кто открыл сундук)
если что-то не понятно - комменты

Код

АХАХАХАХ ТЫ ЧТО ТУТ ЗАБЫЛ РЕАЛЬНА ПАСМАТРЕТЬ РЕШИЛ ЧТОЛИ АПРЫРПАПЫЫСМ РЖУ НЕ МОГУ КАКОЙ ЖЕ ТЫ НАИВНЫЙ НЕ БУДЕТ ТУТ НИКАКОГО КОДА ВПЛРЖОЫПААХАХАХАХХАХАХ
ТУТ ЛИШЬ СПЛОШНОЕ ГОВНО КОТОРОЕ Я НАСРАЛ ОТДУШИ И НЕПРОГЛЯДНОЕ БОЛОТО ДО САМОГО ГОРИЗОНТА И ЭТО ВСЁ МОЁ БОЛОТО, ПОНЯЛ? МОЁЁЁЁЁЫВАПЫВАРЫАВРЫРПД
та лан я шучу, не стукай, вон там можешь умоститься под тем гнилым пеньком, мне тут одиноко. Сейчас принесу тебе чайку, тут много птиц полегло, тебе зелёную?
Chest
library ChestPuzzleLib initializer OnInit requires SoundLib
globals
    private constant group TempGroup = CreateGroup( )
    
    private timer array TempTimer
    
    private integer array CurrentPin
    
    private boolean array PuzzleOpen
    private boolean array LockMoves
    private boolean array MoveKeyUp
    private boolean array MoveSpringUp
    private boolean array SpaceTap
    
    private real array Distance
    private real array DistanceSpring
    private real array Speed
    private real array SpeedSpring
    private real array KeyCurrentX
    private real array KeyCurrentY
    
    private unit array Caster
    private unit array Target
    
    framehandle pGameUI = null
    framehandle LockFrame = null
    framehandle LockKeyFrame = null
    framehandle array LockPinFrame
    framehandle array LockSpringFrame
    
    constant hashtable H = InitHashtable( )

    constant key UnitStructKey
    constant key ChestStructKey
endglobals

struct ChestS
    boolean IsOpen = false
    integer LockedPins = 0
    
    real array SpringHeight[5]
    boolean array PinLock[5]
endstruct

function ParabolaZ takes real h, real d, real x returns real
    return (4 * h / d) * (d - x) * (x / d)
endfunction

native UnitAlive takes unit id returns boolean

// створення фреймів скриньки
function OnInit takes nothing returns nothing
    local integer i = 0
    
    set pGameUI = GetOriginFrame( ORIGIN_FRAME_GAME_UI, 0 )
    
    set LockFrame = CreateFrameByType( "BACKDROP", "LockFrame", pGameUI, "", 0 )
    call SetFrameSize( LockFrame, 0.45, 0.45 )
    call SetFrameAbsolutePoint( LockFrame, FRAMEPOINT_CENTER, 0.425, 0.35 )
    call SetFrameTexture( LockFrame, "lock0.blp", 0, false )
    
    set LockKeyFrame = CreateFrameByType( "BACKDROP", "LockKeyFrame", LockFrame, "", 0 )
    call SetFrameSize( LockKeyFrame, 0.30, 0.07 )
    call SetFrameAbsolutePoint( LockKeyFrame, FRAMEPOINT_LEFT, 0.04, 0.29 )
    call SetFrameTexture( LockKeyFrame, "lock3.blp", 0, false )
    
    loop
        set LockSpringFrame[i] = CreateFrameByType( "BACKDROP", "LockSpringFrame" + I2S( i ), LockFrame, "", 0 )
        call SetFrameRelativePoint( LockSpringFrame[i], FRAMEPOINT_TOPLEFT, LockFrame, FRAMEPOINT_TOPLEFT, 0.1255 + 0.03225 * i, -0.1585 )
        call SetFrameTexture( LockSpringFrame[i], "lock1.blp", 0, false )
        
        set LockPinFrame[i] = CreateFrameByType( "BACKDROP", "LockPinFrame" + I2S( i ), LockSpringFrame[i], "", 0 )
        call SetFrameSize( LockPinFrame[i], 0.025, 0.055 )
        call SetFrameRelativePoint( LockPinFrame[i], FRAMEPOINT_TOP, LockSpringFrame[i], FRAMEPOINT_BOTTOM, -0.0005, 0.00 )
        call SetFrameTexture( LockPinFrame[i], "lock2.blp", 0, false )
        
        set i = i + 1
        exitwhen i >= 5
    endloop
    
    call ShowFrame( LockFrame, false )
endfunction

// закрити головоломку
private function ClosePuzzle takes integer i returns nothing
    if GetLocalPlayer( ) == Player( i ) then
        call ShowFrame( LockFrame, false )
        call CameraSetSmoothingFactor( 0.00 )
        call ResetToGameCamera( 0.10 )
    endif
    
    call PauseTimer( TempTimer[i] )
    
    set PuzzleOpen[i] = false
    set Caster[i] = null
    set Target[i] = null
endfunction

// рух фреймів
private function ChestArrows_2 takes nothing returns nothing
    local integer i = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local boolean LocalPlayer
    local ChestS A
    
    // якщо дистанція розірвана - закрити головоломку
    if not UnitAlive( Caster[i] ) or MathDistanceBetweenPoints( GetUnitX( Caster[i] ), GetUnitY( Caster[i] ), GetUnitX( Target[i] ), GetUnitY( Target[i] ) ) > GetUnitRealField( Caster[i], UNIT_RF_COLLISION_SIZE ) + GetUnitRealField( Target[i], UNIT_RF_COLLISION_SIZE ) + 128.00 then
        set ChestS( LoadInteger( H, GetHandleId( Target[i] ), ChestStructKey ) ).IsOpen = false
        call ClosePuzzle( i )
        return
    endif
    
    if LockMoves[i] then
        set LocalPlayer = ( GetLocalPlayer( ) == Player( i ) )
        
        // переміщення відмички вгору
        if MoveKeyUp[i] then
            if Distance[i] < Speed[i] then
                set Speed[i] = Distance[i]
            endif
            
            set Distance[i] = Distance[i] - Speed[i]
            
            if LocalPlayer then
                call SetFrameAbsolutePoint( LockKeyFrame, FRAMEPOINT_LEFT, KeyCurrentX[i], KeyCurrentY[i] + ParabolaZ( 0.025, 0.025, Distance[i] ) )
            endif
            
            // удар відмички о штифт
            if not ChestS( LoadInteger( H, GetHandleId( Target[i] ), ChestStructKey ) ).PinLock[CurrentPin[i]] and not MoveSpringUp[i] and Distance[i] <= 0.175 then
                set MoveSpringUp[i] = true
                set SpeedSpring[i] = 0.001 // швидкість пружини
                set DistanceSpring[i] = 0.04 // дистанція на яку підняти штифт
                
                if LocalPlayer then
                    call StopSound( gg_snd_KeyHit, false, false )
                    call StartSound( gg_snd_KeyHit )
                endif
            endif
        else // переміщення відмички вліво/вправо
            if RAbsBJ( Distance[i] ) < RAbsBJ( Speed[i] ) then
                set Speed[i] = Distance[i]
            endif
            
            set Distance[i] = Distance[i] - Speed[i]
            
            set KeyCurrentX[i] = KeyCurrentX[i] + Speed[i]
            
            if LocalPlayer then
                call SetFrameAbsolutePoint( LockKeyFrame, FRAMEPOINT_LEFT, KeyCurrentX[i], KeyCurrentY[i] )
            endif
        endif
        
        // переміщення пружини вгору
        if MoveSpringUp[i] then
            if DistanceSpring[i] < SpeedSpring[i] then
                set SpeedSpring[i] = DistanceSpring[i]
            endif
            
            set DistanceSpring[i] = DistanceSpring[i] - SpeedSpring[i]
        
            if DistanceSpring[i] <= 0.00 then
                set MoveSpringUp[i] = false
                set SpaceTap[i] = false
            endif
            
            set A = LoadInteger( H, GetHandleId( Target[i] ), ChestStructKey )
            set A.SpringHeight[CurrentPin[i]] = 0.01 + 0.04 - ParabolaZ( 0.04, 0.04, DistanceSpring[i] )
            
            if LocalPlayer then
                call SetFrameSize( LockSpringFrame[CurrentPin[i]], 0.02, A.SpringHeight[CurrentPin[i]] )
            endif
        endif
        
        // припинення руху
        if RAbsBJ( Distance[i] ) <= 0.00 then
            set MoveKeyUp[i] = false
            
            if not MoveSpringUp[i] then
                set LockMoves[i] = false
            endif
        endif
    endif
    
    call TimerStart( TempTimer[i], 0.01, false, function ChestArrows_2 )
endfunction

// маніпуляції з клавішами
private function ChestArrows takes nothing returns nothing
    local boolean LocalPlayer = ( GetLocalPlayer( ) == GetTriggerPlayer( ) )
    local integer i = GetPlayerId( GetTriggerPlayer( ) )
    local oskeytype k
    local ChestS A
    
    if PuzzleOpen[i] then
        set k = GetTriggerPlayerKey( )
        
        if k == OSKEY_ESCAPE then // закрити головоломку
            set ChestS( LoadInteger( H, GetHandleId( Target[i] ), ChestStructKey ) ).IsOpen = false
            call ClosePuzzle( i )
            return
        endif
        
        if not LockMoves[i] then
            if k == OSKEY_LEFT and CurrentPin[i] > 0 then
                set LockMoves[i] = true
                set CurrentPin[i] = CurrentPin[i] - 1
                set Distance[i] = -0.032 // дистанція зміщення відмички
                set Speed[i] = -0.001 // швидкість переміщення відмички
            elseif k == OSKEY_RIGHT and CurrentPin[i] < 4 then
                set LockMoves[i] = true
                set CurrentPin[i] = CurrentPin[i] + 1
                set Distance[i] = 0.032
                set Speed[i] = 0.001
            elseif k == OSKEY_UP then
                set LockMoves[i] = true
                set MoveKeyUp[i] = true
                set Distance[i] = 0.025
                set Speed[i] = 0.001
            endif
        elseif k == OSKEY_SPACE and MoveSpringUp[i] and not SpaceTap[i] then
            set SpaceTap[i] = true
            
            if DistanceSpring[i] > 0.015 and DistanceSpring[i] < 0.02 then // діапазон для фіксації штифту
                set DistanceSpring[i] = 0.00
                
                set A = LoadInteger( H, GetHandleId( Target[i] ), ChestStructKey )
                set A.PinLock[CurrentPin[i]] = true
                set A.LockedPins = A.LockedPins + 1
                set MoveSpringUp[i] = false
                
                if A.LockedPins > 4 then // замок відчинено
                    if LocalPlayer then
                        call StopSound( gg_snd_FixationSuccessLast, false, false )
                        call StartSound( gg_snd_FixationSuccessLast )
                    endif
                    
                    call SetUnitTimeScale( Target[i], 0.75 )
                    call SetUnitAnimation( Target[i], "morph" )
                    call QueueUnitAnimation( Target[i], "stand alternate" )
                    
                    call Sound.playPoint( "war3mapImported\\ChestOpen.wav", GetUnitX( Target[i] ), GetUnitY( Target[i] ), 600.00, 1500.00, 100 )
                    
                    call CreateItem( 'gold', GetUnitX( Target[i] ), GetUnitY( Target[i] ) )
                    
                    call ClosePuzzle( i )
                    return
                elseif LocalPlayer then // штифт зафіксовано
                    call StopSound( gg_snd_FixationSuccess, false, false )
                    call StartSound( gg_snd_FixationSuccess )
                endif
            elseif LocalPlayer then // невдала спроба фіксації штифту
                call StopSound( gg_snd_FixationFail, false, false )
                call StartSound( gg_snd_FixationFail )
            endif
        endif
    endif
endfunction

// відстежування дистанції між юнітом та скринею
private function CheckDistanceForPuzzle takes nothing returns nothing
    local timer t = GetExpiredTimer( )
    local unit caster = LoadUnitHandle( H, GetHandleId( t ), 0 )
    local unit target = LoadUnitHandle( H, GetHandleId( t ), 1 )
    local integer i = GetPlayerId( GetOwningPlayer( caster ) )
    local ChestS A
    
    if not UnitAlive( caster ) or MathDistanceBetweenPoints( GetUnitX( caster ), GetUnitY( caster ), GetUnitX( target ), GetUnitY( target ) ) <= GetUnitRealField( caster, UNIT_RF_COLLISION_SIZE ) + GetUnitRealField( target, UNIT_RF_COLLISION_SIZE ) + 128.00 then
        set A = LoadInteger( H, GetHandleId( target ), ChestStructKey )
        
        if not A.IsOpen and not PuzzleOpen[i] then
            set A.IsOpen = true
            
            set CurrentPin[i] = 0 // на якому штифті наразі відмичка
            set KeyCurrentX[i] = 0.04 // стартове положення відмички
            set KeyCurrentY[i] = 0.29 // стартова висота відмички
            set MoveKeyUp[i] = false
            set LockMoves[i] = false
            set MoveSpringUp[i] = false
            set SpaceTap[i] = false
            set PuzzleOpen[i] = true
            set Caster[i] = caster
            set Target[i] = target
        
            if TempTimer[i] == null then
                set TempTimer[i] = CreateTimer( )
                
                call SaveInteger( H, GetHandleId( TempTimer[i] ), 0, i )
            endif
            
            call TimerStart( TempTimer[i], 0.00, false, function ChestArrows_2 )
            
            if GetLocalPlayer( ) == Player( i ) then
                set i = 0
                
                loop
                    if not A.PinLock[i] then
                        set A.SpringHeight[i] = 0.05 // висота пружинок, якщо не зафіксовані
                    endif
                    
                    call SetFrameSize( LockSpringFrame[i], 0.02, A.SpringHeight[i] )
                    
                    set i = i + 1
                    exitwhen i >= 5
                endloop
                
                call ShowFrame( LockFrame, true )
                call SetFrameAbsolutePoint( LockKeyFrame, FRAMEPOINT_LEFT, 0.04, 0.29 )
                
                call SetCameraTargetController( target, 0.00, 0.00, false )
                call CameraSetSmoothingFactor( 1.00 )
            endif
        endif
        
        call FlushChildHashtable( H, GetHandleId( t ) )
        call DestroyTimer( t )
        
        call RemoveSavedHandle( H, GetHandleId( caster ), UnitStructKey )
    else
        call TimerStart( t, 0.10, false, function CheckDistanceForPuzzle )
    endif
    
    set t = null
    set caster = null
    set target = null
endfunction

// клік по скрині
function Chest_Actions takes nothing returns nothing
    local unit target = GetOrderTargetUnit( )
    local unit caster = GetTriggerUnit( )
    local timer t
    
    if target != null and GetUnitTypeId( target ) == 'h000' and not ChestS( LoadInteger( H, GetHandleId( target ), ChestStructKey ) ).IsOpen then
        set t = LoadTimerHandle( H, GetHandleId( caster ), UnitStructKey )
        
        if t == null and not PuzzleOpen[GetPlayerId( GetOwningPlayer( caster ) )] then
            set t = CreateTimer( )
            
            call SaveUnitHandle( H, GetHandleId( t ), 0, caster )
            call SaveUnitHandle( H, GetHandleId( t ), 1, target )
            
            call SaveTimerHandle( H, GetHandleId( caster ), UnitStructKey, t )
            
            call TimerStart( t, 0.00, false, function CheckDistanceForPuzzle )
        endif
        
        set t = null
    endif
    
    set target = null
    set caster = null
endfunction

//===========================================================================

// реєстрація скринь на мапі
function RegistChest takes unit u returns nothing
    local ChestS A = ChestS.create( )
    local integer i = 0
    
    set A.IsOpen = false
    set A.LockedPins = 0
    
    loop
        set A.PinLock[i] = false
        
        set i = i + 1
        exitwhen i >= 5
    endloop
    
    call SetUnitSelectable( u, false )
    call SaveInteger( H, GetHandleId( u ), ChestStructKey, A )
endfunction

function InitTrig_Chest takes nothing returns nothing
    local integer i = 0
    local unit u
    local trigger trg = CreateTrigger( )
    local player p
    
    set gg_trg_Chest = CreateTrigger(  )
    set bj_groupEnumTypeId = 'h000' // равкод скрині
    
    loop
        set p = Player( i )
        
        call TriggerRegisterPlayerUnitEvent( gg_trg_Chest, p, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null )
        call TriggerRegisterPlayerUnitEvent( gg_trg_Chest, p, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null )
        call TriggerRegisterPlayerUnitEvent( gg_trg_Chest, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, null )
        
        call TriggerRegisterPlayerKeyEvent( trg, p, OSKEY_LEFT, 0, true )
        call TriggerRegisterPlayerKeyEvent( trg, p, OSKEY_RIGHT, 0, true )
        call TriggerRegisterPlayerKeyEvent( trg, p, OSKEY_UP, 0, true )
        call TriggerRegisterPlayerKeyEvent( trg, p, OSKEY_SPACE, 0, true )
        call TriggerRegisterPlayerKeyEvent( trg, p, OSKEY_ESCAPE, 0, true )
        
        set PuzzleOpen[i] = false
        
        call GroupEnumUnitsOfPlayer( TempGroup, p, filterGetUnitsOfPlayerAndTypeId )
        loop
            set u = FirstOfGroup( TempGroup )
            exitwhen u == null
            call GroupRemoveUnit( TempGroup, u )
            
            call RegistChest( u )
        endloop
        
        set i = i + 1
        exitwhen i >= bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddAction( gg_trg_Chest, function Chest_Actions )
    call TriggerAddAction( trg, function ChestArrows )
endfunction
endlibrary

Sound
library SoundLib
globals
    private constant hashtable H = InitHashtable( )
    private constant real MaxDistance    = 9999999.00 // макс дистанція звуку
    private constant real VisibleXForAll = 0.00 // видимі координати кожному гравцю у будь-який час гри
    private constant real VisibleYForAll = 0.00
    
    private constant location LFZ = Location( 0.00, 0.00 )
endglobals

function GetLocZ takes real x, real y returns real
    call MoveLocation( LFZ, x, y )
    return GetLocationZ( LFZ )
endfunction

struct Sound
    private static hashtable HS = InitHashtable( ) // таблица для звуков, StringHash(string)
    private static real PTIME   = 0.05
    boolean is_playing = false
    integer volume
    integer tick
    sound sound
    timer timer
    unit u
    real x
    real y
    real z
    real time
    real minDist
    real maxDist
    
    // создает и прелоадит новый звук, не использовать!
    // для получения свободного звука из буфера используйте Sound.path2sound(string)
    static method create takes string path, real time returns thistype
        local thistype n = thistype.allocate( )
        local integer hid = StringHash( path )
        local integer count = LoadInteger( HS, hid, 0 ) + 1
        
        set n.sound = CreateSound( path, false, true, false, 10, 10, "" )
        set n.time  = time
        set n.timer = CreateTimer( )
        call SaveInteger( H, 0, GetHandleId( n.timer ), n )
        call SaveInteger( HS, hid, 0, count )
        call SaveInteger( HS, hid, count, n )
        
        call SetSoundDistanceCutoff( n.sound, MaxDistance )
        call SetSoundDistances( n.sound, MaxDistance, MaxDistance )
        call SetSoundConeAngles( n.sound, MaxDistance, MaxDistance, 127 )
        
        return n
    endmethod
    
    method destroy takes nothing returns nothing
        // заглушка, удалять Sound не надо, они кешируются вместе с sound в hashtable
    endmethod
    
    // остановить звук
    method stop takes nothing returns integer
        if this > 0 and .is_playing then
            call PauseTimer( .timer )
            call StopSound( .sound, false, false )
            set .u = null
            set .is_playing = false
        endif
        
        return 0
    endmethod
    
    static method track takes nothing returns nothing
        local thistype snd = LoadInteger( H, 0, GetHandleId( GetExpiredTimer( ) ) )
        local real x
        local real y
        local real z
        local real d
        
        if snd.u != null then
            if GetUnitTypeId( snd.u ) > 0 then
                set x = snd.x
                set y = snd.y
                set z = snd.z
                
                set snd.x = GetUnitX( snd.u )
                set snd.y = GetUnitY( snd.u )
                set snd.z = GetLocZ( snd.x, snd.y ) + GetUnitFlyHeight( snd.u )
                
                if x != snd.x or y != snd.y or z != snd.z then
                    call SetSoundPosition( snd.sound, snd.x, snd.y, snd.z )
                endif
            else
                set snd.u = null
            endif
        endif
            
        set x = GetCameraTargetPositionX( )
        set y = GetCameraTargetPositionY( )
        set z = GetCameraTargetPositionZ( )
        set d = SquareRoot( ( x - snd.x ) * ( x - snd.x ) + ( y - snd.y ) * ( y - snd.y ) + ( z - snd.z ) * ( z - snd.z ) )
        
        if d > snd.minDist then
            if d > snd.maxDist then
                call SetSoundVolume( snd.sound, 0 )
            else
                call SetSoundVolume( snd.sound, R2I( snd.volume * ( 1.00 - ( ( d - snd.minDist ) / ( snd.maxDist - snd.minDist ) ) ) ) )
            endif
        else
            call SetSoundVolume( snd.sound, snd.volume )
        endif
        
        set snd.tick = snd.tick - 1
        
        if snd.tick <= 0 then
            call snd.stop( )
        else
            call TimerStart( snd.timer, PTIME, false, function thistype.track )
        endif
    endmethod
    
    // проиграть звук в точке
    method play takes nothing returns nothing
        if this <= 0 then
            return
        endif
        
        call SetSoundPosition( .sound, VisibleXForAll, VisibleYForAll, 0.00 )
        call StartSound( .sound )
        
        call SetSoundPosition( .sound, .x, .y, z )
        call SetSoundVolume( .sound, .volume )
        call SetSoundPitch( .sound, GetRandomReal( 0.98, 1.02 ) )
        call SetSoundConeOrientation( .sound, .x, .y, z )
        
        set .is_playing = true
        
        set .tick = R2I( .time / PTIME ) + 1
        call TimerStart( .timer, 0.00, false, function thistype.track )
    endmethod
    
    // получить звук по пути (если нет свободного звука создется новый)
    static method path2sound takes string path returns thistype
        local integer hid = StringHash( path )
        local integer count = LoadInteger( HS, hid, 0 )
        local integer i = 1
        local Sound snd
        
        if count <= 0 then
            return 0
        endif
        
        loop
            exitwhen i > count
            set snd = LoadInteger( HS, hid, i )
            
            if not snd.is_playing then
                return snd
            endif 
            
            set i = i + 1
        endloop
        
        return Sound.create( path, thistype( LoadInteger( HS, hid, 1 ) ).time )
    endmethod
    
    // проиграть звук в точке
    static method playPoint takes string path, real x, real y, real mind, real maxd, integer vol returns thistype
        local thistype snd = path2sound( path )
        
        set snd.x = x
        set snd.y = y
        set snd.z = GetLocZ( snd.x, snd.y )
        set snd.minDist = mind
        set snd.maxDist = maxd
        set snd.volume  = vol
        call snd.play( )
        
        return snd
    endmethod
    
    // проиграть звук на юните
    static method playUnit takes string path, unit u, real mind, real maxd, integer vol returns thistype
        local thistype snd = path2sound( path )
        
        set snd.u = u
        set snd.x = GetUnitX( u )
        set snd.y = GetUnitY( u )
        set snd.z = GetLocZ( snd.x, snd.y ) + GetUnitFlyHeight( u )
        set snd.minDist = mind
        set snd.maxDist = maxd
        set snd.volume  = vol
        call snd.play( )
        
        return snd
    endmethod

    // прелоадит звук в библиотеку. все звуки нужно прелоадить 1 раз.
    static method preload takes string path, real time returns nothing
        call thistype.create( path, time )
    endmethod
endstruct
endlibrary

//===========================================================================
function InitTrig_Sound takes nothing returns nothing
    //set gg_trg_Sound = CreateTrigger(  )
    call Sound.preload( "war3mapImported\\ChestOpen.wav", 1.22 )
endfunction


Несуществующие планы

Это можете доработать и сами

Головоломку можно усложнить, кстати.
Добавить, что фиксация предыдущих штифтов сбрасывается при непрожатии следующего, либо спустя какое то время (т.е. ломать замок надо быстро). Штифт падает, ломает отмычку и жизнь игрока.
Можно регулировать сложность замка, меняя количество штифтов и время до тех пор, как штифт упадёт.
А отмычки доступны в ограниченном количестве, и их надо искать, покупать, или крафтить.
`
ОЖИДАНИЕ РЕКЛАМЫ...
28
нафиг тебе .toc файл в карте если ты не юзаешь его в коде? в чём прикол?
Ответы (1)
28
rsfghd, я первый раз что-то делал на южапи, закинул по привычке необходимости, потом увидел возможность создания фреймов без ток файла, просто забыл убрать этот огрызок, но ты прав, мне нужно вскры
23
Подскажите название трека на фоне, пожалуйста)
Механика хороша, почти Скайрим получился. П. С. Так ведь южапи может ловить координаты мышки и кнопок, можно в теории 1 в 1 реализовать замки, как в скайриме...
Ответы (3)
28
EugeAl, этот замочек из Обливиона вроде, и если не ошибаюсь там тоже можно мышкой ковыряться. Первобытная моя задумка тоже включала манипуляции с мышкой, но я так не удобно реализовал это на месхаке, что решил на стрелочках сделать
23
rsfghd, а, понял. Ну да, в скайриме вроде другой был.
За трек спасибо)
Ответы (1)
30
Ryabte, а как в фоллауте? Можно видос? А в идеале, вообще видос со всеми типами вщлома в играх?
Во, сам нашёл. www.youtube.com/watch?v=-DsaOMn4lAw
20
Отличная наработка, конечно в плане кода мало на что смотреть, зато идея вполне интересная и полезная. Молодец.
Ответы (2)
28
Unryze, я хотел ещё одну головоломку сделать с мозаикой, но возникли проблемы с центрированием этих кусков, поэтому возможно чуть позже закину то, о чём так сильно мечтал - систему шутера в мультиплеере. Но энивей я не думаю что там много чего нового будет использовано. События новые на клавиши да и работа с эффектами, всё. Тем не менее в планах ещё одна интересная вещь для стрельбы от первого лица
P.s. я понимаю что вышеперечисленное не будет оцениваться в конкурсе, это для развития южапи. Кстати, у меня порой не с первого раза запускается проверка из редактора
20
rsfghd, на конкурс ты можешь выставлять эту работу спокойно, да и другую тоже, этим я никого ограничивать не собираюсь. А по поводу запуска карты, не знаю к сожалению, ибо у кого были проблемы (включая меня) их уже нет. всё что можно было прооптимизировать - я оптимизировал.
15
Офигеть, это же взлом из Обливион, написанные на jass. Поражаешь, насколько ты потный товарищ однако) Красава, это ж надо было додуматься, пилить такое на движке варика xD
Чтобы оставить комментарий, пожалуйста, войдите на сайт.