IzobretatelBoom, я создал дополнительную логическую переменную, которая проверяет был ли создан погодный эффект. Если да, то эффект удаляется. Вроде от некоторых фризов это избавило. Но всё равно глобально вызывание погодного эффекта создаёт фриз, ничего не сделать как я понимаю.
Функция Wait у меня создана, потому что если удалить и создать эффект одновременно, возникнет баг звука. И звук погодного эффекта может остаться навсегда.
Нашёл в чём ещё была проблема. В редакторе ИИ я неверно указал последовательность строительства войск и апгрейдов. А когда ИИ не видит возможность выполнить приказ, он начинает жёстко фризить. Поэтому он фризит если в списке целей у него есть покупка дирижаблей.
ShadowNinja, в общем собрал такой же ИИ. И точно такой же баг. На этот раз сразу после создания Замка. Непонятно в чём дело. Варкрафт задолбал. В нём ничего никогда не работает.
EugeAl, не сбивает. Я включил ложный путь для ИИ скрипта. ИИ ничего не делал, только способности автоматически использовал. Но он не уводил назад раненых. Но если это сбивает приказ, то и не нужно. Хотя бы придумать как активировать автокаст способностей. Если включить ИИ для человека, он не активируется никак.
ApEJI, вся проблема только в том, что эффект должен быть привязан к герою. А в редакторе объектов масштаб эффектов способностей не масштабируется. Ну что ж, придётся вернуться к функции move unit.
Уважаемый автор, мне очень понравилась твоя модель. Я создал способность огненного купола для эльфийского паладина. Все, кто находится в куполе, имеют невосприимчивость к дальнобойному урону и магии. Я создал 3 уровня способности, и чем выше уровень, тем больше становится купол. Изначально я создал даммика, который каждые 0.01 секунды телепортируется к герою. Но в целях оптимизации, я решил сделать 3 версии эффекта разного размера, и прикреплять его к герою. С помощью ME я кривыми ручками просто увеличил масштаб, и получил такой артефакт:
Скажи, можно ли как-то через ME добиться масштабирования 0.9, 1.35 и 1.85 для этой модели? Или иными оптимизированными путями добаиться адекватного скейлинга? Или может тебе не трудно дополнительно залить разные версии масштабирования?
Но выбор юнитов в группу на гуи будет в любом случае утечен из-за необнуления локалки в одной из функций в коде
rsfghd, а если я эту группу использую одноразово, и затем удаляю через Destroy (в кастомном редакторе варика эта функция есть)?
Если всё равно утечка, то получается, мне через гуи остаётся только создать перманентную группу, которую просто периодически очищать, и добавлять туда юнитов по одному (например при реакции на какое-то событие)?
Вообще это проблема. У меня в карте несколько периодичных триггеров для ауры, которые постоянно создают-удаляют группу. Если будут играть 24 игрока героями, юзающими эти триггеры, то фризы обеспечены. Похоже, придётся через джасс это делать.
Выходит, что у нас массив по-умолчанию = 1, и если я переназначу переменную с индексом = 1 через Create Group, то будет утечка группы, которая была создана при инициализации карты?
rsfghd, можно ли это как-то оптимизировать? Если указать массив = 1, но в триггерах указать группу через Set Variable например индекс 24, у меня создастся 24 группы или останется только 1-ая и 24-ая?
Ещё вопрос, на случай если ответ - групп будет две:
А если я буду через условия перебирать индекс от 1 до 24, у меня не будут в результате проверки создаваться группы?
Infernall, ого! Большое спасибо, не ожидал, да ещё и так оперативно. Сейчас буду пробовать поменять масштаб. Подскажите, какие параметры крутить у аттача?
Каким образом в этой программе редактировать поворот кости? Даётся 4 параметра для редактирования. Не совсем понятно что это за параметры, и нигде не написано что это за оси. Допустим, первые 2 это X и Y. Тогда остальные 2 что значат?
Исправьте пожалуйста модель, чтобы к Chest можно было прикрепить нормально броню. Я ковырялся в ME, так и не смог этого добиться. Например, меняю поворот - меняется масштаб. Меняю масштаб - ничего не происходит. И т.д. В общем я не шарю в этом. Авторство укажу!
Нашёл в чём была причина. Она оказалась не в скрипте. Дело в том, что в моей карте использовался ежесекундный реплейсмент зданий. И почему-то при создании холла нежити, оно издавало звук, но не в месте его создания, а в центре карты. Ещё какой-то из холлов создавал звук сотворения водного элема. Это было трудно отследить, потому что после выбора расы, триггер прекращал действовать, и звуки исчезали. Но если кто-то из игроков её не выбирал, звуки продолжались.
EugeAl, нет, на пустой карте такой баг не встречается. Но именно активация скрипта инициализирует баг. (Полный код в посте ниже.) Может какие-то переменные перекликаются. Но я прочёл код, и хотя плохо разбираюсь в jass, не нашёл ничего что могло бы вызывать эти звуки. Буду разбираться.
Makeba, да, точно, верное замечание. Действительно, у меня в корне карты есть этот код. Я делал это давно, и уже забыл. Запомнил что автор когда говорил что он сделан Blizzard, и мне запомнилось что он вшит в игру, но оказалось это не так. Вот изменённый код автора, который у меня в карте:
//===========================================================================
// Counts key structures owned by a player and his or her allies, including
// structures currently upgrading or under construction.
//
// Key structures: Town Hall, Great Hall, Tree of Life, Necropolis
//
function LivingPlayerHallsFilter takes nothing returns boolean
return (IsUnitAliveBJ(GetFilterUnit()) and IsUnitType(GetFilterUnit(),UNIT_TYPE_TOWNHALL))
endfunction
function CountLivingPlayerTownHalls takes player whichPlayer returns integer
local group g
local integer matchedCount
local boolexpr b=Filter(function LivingPlayerHallsFilter)
set g = CreateGroup()
call GroupEnumUnitsOfPlayer(g, whichPlayer, b)
set matchedCount = CountUnitsInGroup(g)
call DestroyGroup(g)
call DestroyBoolExpr(b)
set b=null
set g=null
return matchedCount
endfunction
function Custom_MeleeGetAllyKeyStructureCount takes player whichPlayer returns integer
local integer playerIndex
local player indexPlayer
local integer keyStructs
// Count the number of buildings controlled by all not-yet-defeated co-allies.
set keyStructs = 0
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
if (PlayersAreCoAllied(whichPlayer, indexPlayer)) then
set keyStructs = keyStructs + CountLivingPlayerTownHalls(indexPlayer)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "townhall", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "greathall", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "treeoflife", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "necropolis", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h030", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h01C", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h012", true, true)
// set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "custom_h013", true, true)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h013',indexPlayer)//Never use group functions for this, just count living units for player. Much better idea.
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h014',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h015',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01C',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01E',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h01F',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h012',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h02F',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h02J',indexPlayer)
// set keyStructs = keySructs + CountLivingPlayerUnitsOfTypeId('h030',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h000',indexPlayer)//Non-modded human custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h00D',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('h00E',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00C',indexPlayer)//Non-modded orc custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00D',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('o00E',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00M',indexPlayer)//Non-modded night elf custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00N',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('e00O',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00C',indexPlayer)//Non-modded undead custom ids
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00D',indexPlayer)
// set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId('u00E',indexPlayer)
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
return keyStructs
endfunction
//===========================================================================
function Custom_MeleePlayerIsCrippled takes player whichPlayer returns boolean
local integer allyStructures = MeleeGetAllyStructureCount(whichPlayer)
local integer allyKeyStructures = Custom_MeleeGetAllyKeyStructureCount(whichPlayer)
// Dead teams are not considered to be crippled.
return (allyStructures > 0) and (allyKeyStructures <= 0)
endfunction
//===========================================================================
// Test each player to determine if anyone has become crippled.
//
function Custom_MeleeCheckForCrippledPlayers takes nothing returns nothing
local integer playerIndex
local player indexPlayer
local force crippledPlayers = CreateForce()
local boolean isNowCrippled
local race indexRace
// The "finish soon" exposure of all players overrides any "crippled" exposure
if bj_finishSoonAllExposed then
return
endif
// Check each player to see if he or she has been crippled or uncrippled.
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
set isNowCrippled = Custom_MeleePlayerIsCrippled(indexPlayer)
if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then
// Player became crippled; start their cripple timer.
set bj_playerIsCrippled[playerIndex] = true
call TimerStart(bj_crippledTimer[playerIndex], bj_MELEE_CRIPPLE_TIMEOUT, false, function MeleeCrippledPlayerTimeout)
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Show the timer window.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)
// Display a warning message.
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, "|cffffcc00"+udg_RevealWarning+"|r")
endif
elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then
// Player became uncrippled; stop their cripple timer.
set bj_playerIsCrippled[playerIndex] = false
call PauseTimer(bj_crippledTimer[playerIndex])
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Hide the timer window for this player.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
// Display a confirmation message if the player's team is still alive.
if (MeleeGetAllyStructureCount(indexPlayer) > 0) then
if (bj_playerIsExposed[playerIndex]) then
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNREVEALED"))
else
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNCRIPPLED"))
endif
endif
endif
// If the player granted shared vision, deny that vision now.
call MeleeExposePlayer(indexPlayer, false)
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
endfunction
//===========================================================================
// Determine if the lost unit should result in any defeats or victories.
//
function Custom_MeleeCheckLostUnit takes unit lostUnit returns nothing
local player lostUnitOwner = GetOwningPlayer(lostUnit)
// We only need to check for mortality if this was the last building.
if (GetPlayerStructureCount(lostUnitOwner, true) <= 0) then
call MeleeCheckForLosersAndVictors()
endif
// Check if the lost unit has crippled or uncrippled the player.
// (A team with 0 units is dead, and thus considered uncrippled.)
call Custom_MeleeCheckForCrippledPlayers()
endfunction
//===========================================================================
// Determine if the gained unit should result in any defeats, victories,
// or cripple-status changes.
//
function Custom_MeleeCheckAddedUnit takes unit addedUnit returns nothing
local player addedUnitOwner = GetOwningPlayer(addedUnit)
// If the player was crippled, this unit may have uncrippled him/her.
if (bj_playerIsCrippled[GetPlayerId(addedUnitOwner)]) then
call Custom_MeleeCheckForCrippledPlayers()
endif
endfunction
//===========================================================================
function Custom_MeleeTriggerActionConstructCancel takes nothing returns nothing
call Custom_MeleeCheckLostUnit(GetCancelledStructure())
endfunction
//===========================================================================
function Custom_MeleeTriggerActionUnitDeath takes nothing returns nothing
if (IsUnitType(GetDyingUnit(), UNIT_TYPE_STRUCTURE)) then
call Custom_MeleeCheckLostUnit(GetDyingUnit())
endif
endfunction
//===========================================================================
function Custom_MeleeTriggerActionUnitConstructionStart takes nothing returns nothing
call Custom_MeleeCheckAddedUnit(GetConstructingStructure())
endfunction
//===========================================================================
function Custom_MeleeTriggerActionAllianceChange takes nothing returns nothing
call MeleeCheckForLosersAndVictors()
call Custom_MeleeCheckForCrippledPlayers()
endfunction
//===========================================================================
function MeleeInitVictoryDefeatCustomized takes nothing returns nothing
local trigger trig
local integer index
local player indexPlayer
// Create a timer window for the "finish soon" timeout period, it has no timer
// because it is driven by real time (outside of the game state to avoid desyncs)
set bj_finishSoonTimerDialog = CreateTimerDialog(null)
// Set a trigger to fire when we receive a "finish soon" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_SOON)
call TriggerAddAction(trig , function MeleeTriggerTournamentFinishSoon)
// Set a trigger to fire when we receive a "finish now" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig , EVENT_GAME_TOURNAMENT_FINISH_NOW)
call TriggerAddAction(trig , function MeleeTriggerTournamentFinishNow)
// Set up each player's mortality code.
set index = 0
loop
set indexPlayer = Player(index)
// Make sure this player slot is playing.
if ( GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING ) then
set bj_meleeDefeated[index]=false
set bj_meleeVictoried[index]=false
// Create a timer and timer window in case the player is crippled.
set bj_playerIsCrippled[index]=false
set bj_playerIsExposed[index]=false
set bj_crippledTimer[index]=CreateTimer()
set bj_crippledTimerWindows[index]=CreateTimerDialog(bj_crippledTimer[index])
call TimerDialogSetTitle(bj_crippledTimerWindows[index] , MeleeGetCrippledTimerMessage(indexPlayer))
// Set a trigger to fire whenever a building is cancelled for this player.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL , null)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionConstructCancel)
// Set a trigger to fire whenever a unit dies for this player.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_DEATH , null)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitDeath)
// Set a trigger to fire whenever a unit begins construction for this player
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig , indexPlayer , EVENT_PLAYER_UNIT_CONSTRUCT_START , null)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionUnitConstructionStart)
// Set a trigger to fire whenever this player defeats-out
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_DEFEAT)
call TriggerAddAction(trig , function MeleeTriggerActionPlayerDefeated)
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)
// Set a trigger to fire whenever this player changes his/her alliances.
set trig = CreateTrigger()
call TriggerRegisterPlayerAllianceChange(trig , indexPlayer , ALLIANCE_PASSIVE)
call TriggerRegisterPlayerStateEvent(trig , indexPlayer , PLAYER_STATE_ALLIED_VICTORY , EQUAL , 1)
call TriggerAddAction(trig , function Custom_MeleeTriggerActionAllianceChange)
else
set bj_meleeDefeated[index]=true
set bj_meleeVictoried[index]=false
// Handle leave events for observers
if ( IsPlayerObserver(indexPlayer) ) then
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig , indexPlayer , EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig , function MeleeTriggerActionPlayerLeft)
endif
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
// Test for victory / defeat at startup, in case the user has already won / lost.
// Allow for a short time to pass first, so that the map can finish loading.
call TimerStart(CreateTimer() , 2.0 , false , function Custom_MeleeTriggerActionAllianceChange)
endfunction
Осталось только понять, что может вызывать этот баг. Буду пробовать решить. Если найду причину - оставлю здесь пост.
Мне кажется, в RTS первый вариант модели смотрится лучше. Из-за вида сверху, восприятие моделек немного меняется. Оригинальный варик не просто так диспропорциональный.
nazarpunk, бро, вопросы существуют для обмена опытом. Если ты никогда не делал ничего подобного, тогда скипай вопрос. В чём проблема? Тебя никто не принуждает отвечать.
EugeAl, хотя... Сделал синфазность всех костей, и получилось уже нормально:
Меня устраивает такой результат. Правда непонятно зачем аура двигается с героем. В чём смысл. Но ладно, пусть будет. Так все ауры в варкрафте поворачиваются, зачем-то.
Ред. WilliamBz
» WarCraft 3 / Почему удаление несуществующего погодного эффекта удаляет другой погодный эффект?
» WarCraft 3 / Фризы при ИИ с кастомной расой
Ред. WilliamBz
» Stormgate / Аллен Диллинг вкатился в Stormgate
» WarCraft 3 / Почему ИИ не делает кастомный апгрейд?
Ред. WilliamBz
» WarCraft 3 / Включить ИИ для игрока-человека
» WarCraft 3 / Почему ИИ не делает кастомный апгрейд?
» WarCraft 3 / Надо ли очищать группу перед уничтожением
» WarCraft 3 / Огненный купол
» WarCraft 3 / Огненный купол
Ред. WilliamBz
» WarCraft 3 / Можно ли использовать универсальные переменные?
Ред. WilliamBz
» WarCraft 3 / Можно ли использовать универсальные переменные?
Ред. WilliamBz
» WarCraft 3 / Можно ли использовать универсальные переменные?
» WarCraft 3 / Можно ли использовать универсальные переменные?
» WarCraft 3 / Нужна модель? - Вам сюда!
Ред. WilliamBz
» WarCraft 3 / Нужна модель? - Вам сюда!
» WarCraft 3 / War3 Model Editor 1.07 (RU)
Ред. WilliamBz
» WarCraft 3 / Нужна модель? - Вам сюда!
Ред. WilliamBz
» WarCraft 3 / Replace холла создаёт посторонние звуки в центре карты
» WarCraft 3 / Replace холла создаёт посторонние звуки в центре карты
Ред. WilliamBz
» WarCraft 3 / Replace холла создаёт посторонние звуки в центре карты
» Stormgate / Stormgate, анонс обновления 0.1.0
» WarCraft 3 / Будет ли работать в Reforged функция "Hide Ability"?
Ред. WilliamBz
» WarCraft 3 / Replace холла создаёт посторонние звуки в центре карты
» WarCraft 3 / Можно ли прикрепить эффект к Origin, но без поворота юнита?
Ред. WilliamBz
» WarCraft 3 / Можно ли прикрепить эффект к Origin, но без поворота юнита?