Демонстрация
С помощью 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
Несуществующие планы
Это можете доработать и сами
Головоломку можно усложнить, кстати.
Добавить, что фиксация предыдущих штифтов сбрасывается при непрожатии следующего, либо спустя какое то время (т.е. ломать замок надо быстро). Штифт падает, ломает отмычку и жизнь игрока.
Можно регулировать сложность замка, меняя количество штифтов и время до тех пор, как штифт упадёт.
А отмычки доступны в ограниченном количестве, и их надо искать, покупать, или крафтить.
вскрыРед. rsfghd
Ред. nazarpunk