Проблема состоит в том, что когда я приказываю проиграть 1 звук в двух разных точках, он проигрывается только в первой. Есть догадка что это такой баг варовского движка, но это моя первая попытка работать со звуком, так что может чего-то не понимаю.
код
globals
hashtable Hash = InitHashtable() // Хеш-таблица
real gateOnCasterOffset = 265 // Расстояние до портала, появляющегося перед героем
real ManaPerSecond = 4.5 //Магии в секунду
real relaseTime = 9.3 // Время в сек, за которое портал активируется
real gateUnkeep = 0.45 // Время (в секундах), через которое порталы перестануть работать в случае срыва/отмены заклинания
real spellSoundFullDistance = 450.0 // Расстояние, на котором звук заклинания проигрывается на полную громкость
real spellSoundScatteringDistance = 1450.0 // Расстояние, на котором громкость звукового эффекта угасает (если расстояние больше - эффект вовсе не слышен)
endglobals
function GetUnitZ takes unit WhichUnit returns real
local location UnitLoc = Location(GetUnitX(WhichUnit),GetUnitY(WhichUnit))
local real UnitZ = GetLocationZ(UnitLoc)+GetUnitFlyHeight(WhichUnit)
call RemoveLocation(UnitLoc)
return UnitZ
endfunction
function removePortals takes nothing returns nothing //Функция для удаления порталов спустя некоторое время после завершения каста
local sound soundHandle01
local timer LifetimeAfterCast = GetExpiredTimer()
local integer LifetimeAftercastEnd = GetHandleId(LifetimeAfterCast)
local unit gateOnCaster = LoadUnitHandle(Hash,LifetimeAftercastEnd,0)
local unit gateOnTargetPoint = LoadUnitHandle(Hash,LifetimeAftercastEnd,1)
local unit Caster = LoadUnitHandle(Hash,LifetimeAftercastEnd,5)
call KillUnit(gateOnCaster) // Юнитов не удаляю, так как предполагаю что это будет делать отдельная система
call SetUnitAnimation(gateOnCaster, "Death")
call KillUnit(gateOnTargetPoint)
call SetUnitAnimation(gateOnTargetPoint, "Death")
call IssueImmediateOrder(Caster,"stop")
call DestroyTimer(GetExpiredTimer())
set gateOnCaster = null
set gateOnTargetPoint = null
endfunction
function gateActivating takes nothing returns nothing //Активируем порталы
local timer gateActivatingTimer = GetExpiredTimer() //Ловим таймер, по истечению которого должны заработать порталы
local integer Id1 = GetHandleId(gateActivatingTimer) //Берём его id
local unit gateOnCaster = LoadUnitHandle(Hash,Id1,0) //Выгружаем юнита (портал возле героя) по id таймера, в ячейке 0
local unit gateOnTargetPoint = LoadUnitHandle(Hash,Id1,1) //Выгружаем юнита (портал в точке применения скилла) по id таймера, в ячейке 1
local location OnCaster = GetUnitLoc(gateOnCaster) //Считываем локацию (положение) портала возле героя. Т.к. чтоб задать точку перенесения порталу нужна именно локация
local location OnTargetPoint = GetUnitLoc(gateOnTargetPoint) //Считываем локацию (положение) портала в точке применения скилла. Т.к. чтоб задать точку перенесения порталу нужна именно локация
call UnitAddAbility(gateOnCaster,'GFGT') // Тут добавляем абилку портала порталу возле героя
call WaygateSetDestination(gateOnCaster, GetLocationX(OnTargetPoint), GetLocationY(OnTargetPoint)) //Тут, задаём точку ("Локацию"), в которую будет телепортировать юнитов портал возле героя
call WaygateActivate (gateOnCaster,true) //Тут запускаем портал возле героя
call UnitAddAbility(gateOnTargetPoint,'GFGT') // Тут добавляем абилку портала порталу в точке применения скилла
call WaygateSetDestination(gateOnTargetPoint, GetLocationX(OnCaster), GetLocationY(OnCaster)) //Тут, задаём точку ("Локацию"), в которую будет телепортировать юнитов портал в точке применения скилла
call WaygateActivate (gateOnTargetPoint,true) //Тут запускаем портал в точке применения скилла
call RemoveLocation(OnCaster) //Тут очищаем записи о переменной типа "Локация"/удаляем локацию
call RemoveLocation(OnTargetPoint) //Тут очищаем записи о переменной типа "Локация"/удаляем локацию
set gateOnCaster = null //Удаляем записи о юните (портеле возле героя), внутри этой функции
set gateOnTargetPoint = null //Удаляем записи о юните (портеле в точке применения скилла), внутри этой функции
call DestroyTimer(gateActivatingTimer) //Удаляем таймер, запустивший эту функцию
endfunction
function gateEffect takes nothing returns nothing // Функция проверяет поддерживает ли герой спелл
local timer gateEffectPeriodical = GetExpiredTimer() //Ловим истекающий таймер (тот, что периодический)
local integer Id2 = GetHandleId(gateEffectPeriodical) //Считываем id этого таймера
local unit gateOnCaster = LoadUnitHandle(Hash,Id2,0) //Выгружаем юнита (портал возле героя) за этим id из ячейки 0
local unit gateOnTargetPoint = LoadUnitHandle(Hash,Id2,1) //Выгружаем юнита (портал в точке применения) за этим id из ячейки 0
local unit Caster = LoadUnitHandle(Hash,Id2,2) //Выгружаем кастера из ячейки 0
local timer stopTimer = LoadTimerHandle(Hash,Id2,3) //Выгружаем id таймера, по истечению которого активируются порталы
local sound spellSoundOnCaster = LoadSoundHandle(Hash,Id2,5)
local sound spellSoundOnTarget = LoadSoundHandle(Hash,Id2,6)
local integer Id1
local timer LifetimeAfterCast
local integer LifetimeAftercastEnd
if GetUnitCurrentOrder(Caster) != OrderId("darkportal") or GetUnitState(Caster,UNIT_STATE_MANA)<ManaPerSecond/20 then //Если приказ, который выполняет юнит не равен тому что надо (приказ указан в настройках абилки) или у кастера закончилась мана, тогда
set LifetimeAfterCast = CreateTimer() // Создаём таймер, по истечению которого порталы перестанут работать
call TimerStart(LifetimeAfterCast,gateUnkeep,false,function removePortals) //Стартуем этот таймер как одноразовый, который истечёт через "gateUnkeep" секунд и запустит функцию "removePortals"
set LifetimeAftercastEnd = GetHandleId(LifetimeAfterCast) //Берём id этого таймера
call SaveUnitHandle(Hash,LifetimeAftercastEnd,0,gateOnCaster) //Сохраняем за этим id портал возле героя
call SaveUnitHandle(Hash,LifetimeAftercastEnd,1,gateOnTargetPoint) //Сохраняем за этим id портал у точки применения скилла
call SaveUnitHandle(Hash,LifetimeAftercastEnd,5,Caster) //Сохраняем кастера
set Id1 = LoadInteger(Hash,Id2,4) //Загружаем id таймера, по истечению которого порталы должны были бы активироватся
set gateOnCaster = null //Обнуляем переменные
set gateOnTargetPoint = null //Обнуляем переменные
set Caster = null //Обнуляем переменные
call DestroyTimer(stopTimer) //Удаляем запись о таймере "stopTimer" внутри этой функции
call DestroyTimer(gateEffectPeriodical) //Удаляем периодический таймер, запускающий эту функцию (В этот момент все периодические действия прекращаются)
call FlushChildHashtable(Hash,Id1) //Очищаем хеш-таблицу за ключём по id, таймера, по истечению которого активируются порталы
call FlushChildHashtable(Hash,Id2) //Очищаем хеш-таблицу за ключём по id, периодического таймера, вызывающего эту функцию
else
call SetUnitState(Caster, UNIT_STATE_MANA, GetUnitState(Caster,UNIT_STATE_MANA)-ManaPerSecond/20) //Иначе (если спелл не отменён и не закончилась мана) отнимать ManaPerSecond ед. магии
if SquareRoot(Pow(GetCameraTargetPositionX()-GetUnitX(gateOnCaster),2)+Pow(GetCameraTargetPositionY()-GetUnitY(gateOnCaster),2)+Pow(GetCameraTargetPositionZ()-GetUnitZ(gateOnCaster),2)) <= spellSoundFullDistance then
call SetSoundVolume(spellSoundOnCaster,100)
elseif SquareRoot(Pow(GetCameraTargetPositionX()-GetUnitX(gateOnCaster),2)+Pow(GetCameraTargetPositionY()-GetUnitY(gateOnCaster),2)+Pow(GetCameraTargetPositionZ()-GetUnitZ(gateOnCaster),2)) >= spellSoundFullDistance and SquareRoot(Pow(GetCameraTargetPositionX()-GetUnitX(gateOnCaster),2)+Pow(GetCameraTargetPositionY()-GetUnitY(gateOnCaster),2)+Pow(GetCameraTargetPositionZ()-GetUnitZ(gateOnCaster),2)) <= spellSoundScatteringDistance then
call SetSoundVolume(spellSoundOnCaster,100-R2I(100*(SquareRoot(Pow(GetCameraTargetPositionX()-GetUnitX(gateOnCaster),2)+Pow(GetCameraTargetPositionY()-GetUnitY(gateOnCaster),2)+Pow(GetCameraTargetPositionZ()-GetUnitZ(gateOnCaster),2))-spellSoundFullDistance)/(spellSoundScatteringDistance-spellSoundFullDistance)))
else
call SetSoundVolume(spellSoundOnCaster,0)
endif
if SquareRoot(Pow(GetCameraTargetPositionX()-GetUnitX(gateOnTargetPoint),2)+Pow(GetCameraTargetPositionY()-GetUnitY(gateOnTargetPoint),2)+Pow(GetCameraTargetPositionZ()-GetUnitZ(gateOnTargetPoint),2)) <= spellSoundFullDistance then
call SetSoundVolume(spellSoundOnTarget,100)
elseif SquareRoot(Pow(GetCameraTargetPositionX()-GetUnitX(gateOnTargetPoint),2)+Pow(GetCameraTargetPositionY()-GetUnitY(gateOnTargetPoint),2)+Pow(GetCameraTargetPositionZ()-GetUnitZ(gateOnTargetPoint),2)) >= spellSoundFullDistance and SquareRoot(Pow(GetCameraTargetPositionX()-GetUnitX(gateOnTargetPoint),2)+Pow(GetCameraTargetPositionY()-GetUnitY(gateOnTargetPoint),2)+Pow(GetCameraTargetPositionZ()-GetUnitZ(gateOnTargetPoint),2)) <= spellSoundScatteringDistance then
call SetSoundVolume(spellSoundOnTarget,100-R2I(100*(SquareRoot(Pow(GetCameraTargetPositionX()-GetUnitX(gateOnTargetPoint),2)+Pow(GetCameraTargetPositionY()-GetUnitY(gateOnTargetPoint),2)+Pow(GetCameraTargetPositionZ()-GetUnitZ(gateOnTargetPoint),2))-spellSoundFullDistance)/(spellSoundScatteringDistance-spellSoundFullDistance)))
else
call SetSoundVolume(spellSoundOnTarget,0)
endif
endif
endfunction
function portal_Birth_Init takes nothing returns nothing //Появление портала
//Названия переменных выдумываешь какие хочешь. Только учти что тебе с ними иметь дело
local unit Caster
local player casterOwner
local real unitCasterGateX
local real unitCasterGateY
local location spellTargetLoc
local unit gateOnCaster
local unit gateOnTargetPoint
local timer gateActivatingTimer
local timer gateEffectTimerPeriodic
local integer Id1
local integer Id2
local sound spellSoundOnCaster
local sound spellSoundOnTarget
if GetSpellAbilityId() == 'rift' then //Убедимся что кастуется нужная абилка, пишем свой код геройской абилки
set Caster = GetTriggerUnit() // Заносим кастера в переменную
set casterOwner = GetOwningPlayer(Caster)// Игрок-владелец кастера
set unitCasterGateX = GetUnitX(Caster)+gateOnCasterOffset*Cos(GetUnitFacing(Caster)*bj_DEGTORAD) //Задаём координаты портала перед героем
set unitCasterGateY = GetUnitY(Caster)+gateOnCasterOffset*Sin(GetUnitFacing(Caster)*bj_DEGTORAD) //Задаём координаты портала перед героем
set spellTargetLoc = GetSpellTargetLoc() // Ловим локацию чтобы потом удалить
set gateOnCaster = CreateUnit(casterOwner,'gate',unitCasterGateX,unitCasterGateY,180+GetUnitFacing(Caster)) // Создаёт портал перед героем
set gateOnTargetPoint = CreateUnitAtLoc(casterOwner,'gate',spellTargetLoc,GetUnitFacing(Caster))// Создаёт портал в точке применения
call SetUnitAnimation( gateOnCaster, "Birth" ) //Запускает анимацию появления портала перед героем
call SetUnitAnimation( gateOnTargetPoint, "Birth" ) //Запускает анимацию появления портала перед героем
set gateActivatingTimer = CreateTimer() //Создать таймер, по истечению которого порталам добавится и настроится абилка портала
call TimerStart(gateActivatingTimer,relaseTime,false,function gateActivating) // Запускаем предыдущий таймер. По истечению таймера будет вызваня функция "gateActivating". Чтоб вызвать функцию, необходимо разместить её выше чем ту, в которой ее вызывают
set Id1 = GetHandleId(gateActivatingTimer) //Берем id таймера, по истечению которого должен заработать потрал
call SaveUnitHandle(Hash,Id1,0,gateOnCaster) //Сохраняем в хеш-таблицу портал перед героем, за ключём = id таймера,0, по истечению которого должен заработать потрал
call SaveUnitHandle(Hash,Id1,1,gateOnTargetPoint) //Сохраняем в хеш-таблицу портал в точке применения скилла, за ключём = id таймера,1, по истечению которого должен заработать потрал
set gateEffectTimerPeriodic = CreateTimer() //Создать периодический таймер, по истечению которого (много раз в секунду) будут выполнятся заданные функцией "gateEffect" действия
call TimerStart(gateEffectTimerPeriodic,0.05,true,function gateEffect) // тут 20 раз в секунду отнимаем ману, проверяем какой приказ выполняет герой, не мёртв ли и прочее
set spellSoundOnCaster = CreateSound("Sound\\Ambient\\DoodadEffects\\ShimmeringPortalBirth.wav",false,false,false,10,10,"SpellsEAX")
call SetSoundParamsFromLabel(spellSoundOnCaster,"ShimmeringPortalBirth")
call SetSoundDuration(spellSoundOnCaster,8529)
call SetSoundChannel(spellSoundOnCaster,11)
call StartSound(spellSoundOnCaster) //Запускаем звук появления портала (название переменной состоит из префикса "gg_snd_" и названия переменной в редакторе звука)
set spellSoundOnTarget = CreateSound("Sound\\Ambient\\DoodadEffects\\ShimmeringPortalBirth.wav",false,false,false,10,10,"SpellsEAX")
call SetSoundParamsFromLabel(spellSoundOnTarget,"ShimmeringPortalBirth")
call SetSoundDuration(spellSoundOnTarget,8529)
call SetSoundChannel(spellSoundOnTarget,11)
call StartSound(spellSoundOnTarget) //Запускаем звук появления портала (название переменной состоит из префикса "gg_snd_" и названия переменной в редакторе звука)
set Id2 = GetHandleId(gateEffectTimerPeriodic) //Берём id таймера, отвечающего за периодические действия
call SaveUnitHandle(Hash,Id2,0,gateOnCaster) //Сохраняем за этим id портал перед героем
call SaveUnitHandle(Hash,Id2,1,gateOnTargetPoint) //Сохраняем за этим id портал в точке применения
call SaveUnitHandle(Hash,Id2,2,Caster) //Сохраняем кастующего юнита
call SaveTimerHandle(Hash,Id2,3,gateActivatingTimer) //Сохраняем таймер, по истечению которого портал заработает
call SaveInteger(Hash,Id2,4,Id1) //Сохраняем id таймера, по истечению которого портал заработает
call SaveSoundHandle(Hash,Id2,5,spellSoundOnCaster)
call SaveSoundHandle(Hash,Id2,6,spellSoundOnTarget)
set Caster = null //Обнуляем переменную
set casterOwner = null //Обнуляем переменную
call RemoveLocation(spellTargetLoc) //Удаляем локацию
set gateOnCaster = null //Обнуляем переменную
set gateOnTargetPoint = null //Обнуляем переменную
set gateActivatingTimer = null //Обнуляем переменную
set gateEffectTimerPeriodic = null //Обнуляем переменную
endif
endfunction
function InitTrig_spaceRift takes nothing returns nothing // инит
set gg_trg_spaceRift = CreateTrigger() //Создаёт этот триггер (Инит)
call TriggerRegisterAnyUnitEventBJ( gg_trg_spaceRift, EVENT_PLAYER_UNIT_SPELL_EFFECT ) //Ловит приведение любого скилла, любого юнита на карте в действие
call TriggerAddAction( gg_trg_spaceRift, function portal_Birth_Init ) //Если произошло событие, передаёт соответствующие ему данные в функцию "portal_Birth_Init" и запускает её
endfunction
Карта прикреплена. Так будет легче понять "контекст".
Принятый ответ
Нашёл систему, где звук передаётся в таймер, который истекает через 0 секунд. В результате один и тот же звук может проигрываться несколько раз без всяких проблем. В инетике пишут мол это такой баг движка.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Отредактирован Raised
тут слухи про 27 патч ходят
может пофиксят
хотя так и всю игру переписать легче