Ну это смешно уже. Drulia_san, знаешь, как работает инициализаторы библиотек и что такое потоки?
Инициализация происходит в таком порядке, если не править её инжектом.
раскрыть
function main takes nothing returns nothing
call SetCameraBounds(...) // Устанавливаются границы камеры.
call SetDayNightModels(...) // Какие-то модели дня и ночи, не знаю, что это точно делает.
// Ниже идут звуки окружения и музыка.
call NewSoundEnvironment("Default")
call SetAmbientDaySound("LordaeronSummerDay")
call SetAmbientNightSound("LordaeronSummerNight")
call SetMapMusic("Music", true, 0)
call InitBlizzard() // Инициализация различных звуков, некоторых переменных, лимитов и много чего.
// Инициализация структур с помощью ExecuteFunc().
// Инициализация библиотек с помощью ExecuteFunc().
// Инициализация блоков (scope) с помощью call.
call InitGlobals() // Инициализация глобалок, что сделаны в меню переменных.
// Тут вызываются функции, что создают юнитов, разрушаемые объекты, области, камеры и все их параметры.
call InitCustomTriggers() // Создание триггеров, добавление действий, условий и событий.
call RunInitializationTriggers() // Запуск триггеров инициализации.
endfunction
Скорее всего в твоём инициализаторе происходит деление на 0 или использование необъявленной переменной, или количество действий в нём выходит за лимит операций. Пока эти действия были в инициализаторе библиотеки, они происходили в отдельном от main потоке (потому что инициализатор библиотеки вызывается через ExecuteFunc(), что не ломало всё остальное, но как только ты их вынес из него, ломался уже поток main или его дочерний из RunInitializationTriggers().
Я думаю, что реализация с вычислением лучше всего. А так, этот массив можно сделать глобальным, а нужные значения записывать в инициализаторе библиотеки.
Не так уж страшно он компилится
Хорошо.
Я как-то привык по старинке. Можно вынести функцию isUnitAlive вверх и позволить людям выбирать реализацию.
UnitAlive нужно сначала определить, ибо она есть в common.ai. Потому способ с GetWidgetLife лучше в данной ситуации: не нужно что-то определять и работает быстрее GetUnitState.
И приказ лучше написать численный, а не строчный, но это уже мелочи.
Оборачиваем все RemoveUnit в дебаги или на хук vJass. Убираем использование всех BJ функций, заменяем либо на нативки, либо на свои.
Баг может быть в абсолютно рандомном месте, скидывание куска кода может не всегда помочь.
Можно вот так сделать.
Пусть на ВСЁ голосование отведено 60 секунд.
Нужно сделать триггер, который по прошествии 60 секунд с начала игры удаляет все диалоги.
Событие: Прошло 60 секунд с начала игры.
Действия:
Cinematic - Enable user control for (All players) // Нужно для избежания Alt+F4 бага.
Для числа А от 1 до <число игроков> делать
Если Игрок[А] играет тогда
Удалить Диалог[А]
Иначе
< пусто>
Если все проголосовали раньше, что этот триггер нужно отключить.
function CreatePermanentCorpseLocBJ takes integer style, integer unitid, player whichPlayer, location loc, real facing returns unit
set bj_lastCreatedUnit = CreateCorpse(whichPlayer, unitid, GetLocationX(loc), GetLocationY(loc), facing)
call SetUnitBlendTime(bj_lastCreatedUnit, 0)
if (style == bj_CORPSETYPE_FLESH) then
call SetUnitAnimation(bj_lastCreatedUnit, "decay flesh")
call GroupAddUnit(bj_suspendDecayFleshGroup, bj_lastCreatedUnit)
elseif (style == bj_CORPSETYPE_BONE) then
call SetUnitAnimation(bj_lastCreatedUnit, "decay bone")
call GroupAddUnit(bj_suspendDecayBoneGroup, bj_lastCreatedUnit)
else
// Unknown decay style - treat as skeletal.
call SetUnitAnimation(bj_lastCreatedUnit, "decay bone")
call GroupAddUnit(bj_suspendDecayBoneGroup, bj_lastCreatedUnit)
endif
call TimerStart(bj_delayedSuspendDecayTimer, 0.05, false, null)
return bj_lastCreatedUnit
endfunction
bj_delayedSuspendDecayTimer вызывает эту функцию.
раскрыть
function DelayedSuspendDecay takes nothing returns nothing
local group boneGroup
local group fleshGroup
// Switch the global unit groups over to local variables and recreate
// the global versions, so that this function can handle overlapping
// calls.
set boneGroup = bj_suspendDecayBoneGroup
set fleshGroup = bj_suspendDecayFleshGroup
set bj_suspendDecayBoneGroup = CreateGroup()
set bj_suspendDecayFleshGroup = CreateGroup()
call ForGroup(fleshGroup, function DelayedSuspendDecayStopAnimEnum)
call ForGroup(boneGroup, function DelayedSuspendDecayStopAnimEnum)
call TriggerSleepAction(bj_CORPSE_MAX_DEATH_TIME)
call ForGroup(fleshGroup, function DelayedSuspendDecayFleshEnum)
call ForGroup(boneGroup, function DelayedSuspendDecayBoneEnum)
call TriggerSleepAction(0.05)
call ForGroup(fleshGroup, function DelayedSuspendDecayStopAnimEnum)
call DestroyGroup(boneGroup)
call DestroyGroup(fleshGroup)
endfunction
Что происходит.
Через 0.05 после создания "постоянного" трупа его анимация ставится на паузу, через 8 секунд его разложение ставится на паузу, а если его тип разложение есть flesh, то возвращается нужная анимация с ускорением, а через 0.05 анимация опять ставится на паузу.
Да как хочешь, главное, чтобы тебе и игрокам удобно было. Можно все коэфициенты складывать (то есть броня снижает на 40%, от огня защита 10%, итого урон от огня снижается на 50%), а можно перемножением (в этом случае будет снижение будет 46%).
Результат, сами понимаете, может быть разный.
От перестановки множителей произведение не меняется. Ведь это будет так.
damage * (1 - common armor %) * (1 - fire armor %)
можешь дать им на обучение юнита, которого не видно на панели, без быстрого найма буквой. Тогда у здания появится флажок.
Интересная идея!
Но всё также в силе эти проблемы.
А её можно случайно не туда тыкнуть.
Такое можно реализовать, но могут быть проблемы на границах клеток, так как юзер будет думать, что кликнул куда надо, а значок поставился в клетке рядом.
Я хотя я придумал решение, можно сделать через дабл райтклик. Но это уже как-нибудь потом, пока есть другие проекты, которыми нужно заниматься.
Блок глобалок, что я объявил, и многострочные комментарии /*...*/. PT153:
Переписал код, оставил кое-какие комментарии.
xD, я просто скопипастил создание эффекта, а ведь нужно было убрать под таймером GetSpellTargetUnit().
Вот так верно будет.
раскрыть
globals
constant string Effect_A000 = "Abilities\\Spells\\Orc\\LightningBolt\\LightningBoltMissile.mdx"
constant string AttEffect_A000 = "origin"
endglobals
function spell1_dmg takes nothing returns nothing
local integer h = GetHandleId(GetExpiredTimer())
local unit target = LoadInteger(udg_spells_hashtable, h, 0)
local integer tik_count = LoadInteger(udg_spells_hashtable, h, 2)
// Вместо определения локалки для кастера, сразу пихаем его в UnitDamageTargetBJ.
// Локалку всё также можно определить, но после endif её нужно обнулить.
// set caster = null
call DestroyEffect(LoadEffectHandle(udg_spells_hashtable, h, 3))
if tik_count > 0 then
call UnitDamageTargetBJ(LoadUnitHandle(udg_spells_hashtable, h, 1),/*
*/ target, udg_spell1_dmg_period_count, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC)
call DisplayTextToPlayer(GetLocalPlayer(), 0., 0., I2S(tik_count)) // асинхронно, работает по сети.
call SaveInteger(udg_spells_hashtable, h, 2, tik_count - 1)
call SaveEffectHandle(udg_spells_hashtable, h, 3, AddSpecialEffectTarget(Effect_A000, target, AttEffect_A000))
else
call FlushChildHashtable(udg_spells_hashtable, h) // удаляет все записи с parent ключом h.
call DestroyTimer(GetExpiredTimer()) // удаляет таймер.
endif
set target = null
endfunction
function Trig_spell1_cast_jass_Actions takes nothing returns nothing
local timer t = CreateTimer()
local integer h = GetHandleId(t)
call TimerStart(t, 0.05, true, function spell1_dmg)
call SaveUnitHandle(udg_spells_hashtable, h, 0, GetSpellTargetUnit())
call SaveUnitHandle(udg_spells_hashtable, h, 1, GetSpellAbilityUnit())
call SaveInteger(udg_spells_hashtable, h, 2, udg_spell1_time_period_count)
call SaveEffectHandle(udg_spells_hashtable, h, 3, AddSpecialEffectTarget(Effect_A000, GetSpellTargetUnit(), AttEffect_A000))
set t = null // обнуление.
endfunction
Переписал код, оставил кое-какие комментарии.
Должен быть включён vJass в JNGP.
раскрыть
globals
constant string Effect_A000 = "Abilities\\Spells\\Orc\\LightningBolt\\LightningBoltMissile.mdx"
constant string AttEffect_A000 = "origin"
endglobals
function spell1_dmg takes nothing returns nothing
local integer h = GetHandleId(GetExpiredTimer())
local integer tik_count = LoadInteger(udg_spells_hashtable, h, 2)
// Вместо определения локалок для юнитов, сразу их пихаем в UnitDamageTargetBJ.
// Локалки всё также можно определить, но после endif их нужно обнулить.
// set caster = null и set target = null
call DestroyEffect(LoadEffectHandle(udg_spells_hashtable, h, 3))
if tik_count > 0 then
call UnitDamageTargetBJ(LoadUnitHandle(udg_spells_hashtable, h, 1),/*
*/ LoadUnitHandle(udg_spells_hashtable, h, 0),/*
*/ udg_spell1_dmg_period_count, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC)
call DisplayTextToPlayer(GetLocalPlayer(), 0., 0., I2S(tik_count)) // асинхронно, работает по сети.
call SaveInteger(udg_spells_hashtable, h, 2, tik_count - 1)
call SaveEffectHandle(udg_spells_hashtable, h, 3, AddSpecialEffectTarget(Effect_A000, GetSpellTargetUnit(), AttEffect_A000))
else
call FlushChildHashtable(udg_spells_hashtable, h) // удаляет все записи с parent ключом h.
call DestroyTimer(GetExpiredTimer()) // удаляет таймер.
endif
endfunction
function Trig_spell1_cast_jass_Actions takes nothing returns nothing
local timer t = CreateTimer()
local integer h = GetHandleId(t)
call TimerStart(t, 0.05, true, function spell1_dmg)
call SaveUnitHandle(udg_spells_hashtable, h, 0, GetSpellTargetUnit())
call SaveUnitHandle(udg_spells_hashtable, h, 1, GetSpellAbilityUnit())
call SaveInteger(udg_spells_hashtable, h, 2, udg_spell1_time_period_count)
call SaveEffectHandle(udg_spells_hashtable, h, 3, AddSpecialEffectTarget(Effect_A000, GetSpellTargetUnit(), AttEffect_A000))
set t = null
endfunction
Ред. PT153
» WarCraft 3 / Дыхание...
bazeba:
Ред. PT153
» WarCraft 3 / Перестала работать инициализация
Drulia_san, знаешь, как работает инициализаторы библиотек и что такое потоки?
Инициализация происходит в таком порядке, если не править её инжектом.
» WarCraft 3 / ZinC: Сон AOE
» WarCraft 3 / Удаляется герой рандомно, баг
Баг может быть в абсолютно рандомном месте, скидывание куска кода может не всегда помочь.
» XGM Конкурсы / Warcraft 3 Custom Maps Contest 2019
Ред. PT153
» WarCraft 3 / ZinC: Сон AOE
» WarCraft 3 / Отследить что все игроки закрыли диалоговое окно.
Пусть на ВСЁ голосование отведено 60 секунд.
Нужно сделать триггер, который по прошествии 60 секунд с начала игры удаляет все диалоги.
» WarCraft 3 / Отследить что все игроки закрыли диалоговое окно.
В мультиплеере можно через время закрыть, в сингле только через Alt+F4 баг, но я не пробовал так.
» WarCraft 3 / ZinC: Сон AOE
Ред. PT153
» WarCraft 3 / Где можно найти список адресов функции war3map.j
» WarCraft 3 / Отследить что все игроки закрыли диалоговое окно.
PyCCKuu_4eJl:
Ред. PT153
» WarCraft 3 / IFDEBUG 2: Как жить без фаталов?
Я не понял, что тут делает whichPlayer.
» XGM Конкурсы / Warcraft 3 Custom Maps Contest 2019
Ред. PT153
» WarCraft 3 / Вопрос по трупам
Через 0.05 после создания "постоянного" трупа его анимация ставится на паузу, через 8 секунд его разложение ставится на паузу, а если его тип разложение есть flesh, то возвращается нужная анимация с ускорением, а через 0.05 анимация опять ставится на паузу.
Попробуй выбрать другой тип разложения.
» WarCraft 3 / Вопрос по трупам
» WarCraft 3 / Вопрос по трупам
» WarCraft 3 / Дайте совет по алгоритму фильтрации урона различными защитами
» WarCraft 3 / Super tic-tac-toe
Но всё также в силе эти проблемы.
» WarCraft 3 / Динамический диалог
» WarCraft 3 / Влияние освещения на кинематик фильтр
» WarCraft 3 / Пиратка против лицензии.
» XGM Конкурсы / Warcraft 3 Custom Campaign Contest 2019
» WarCraft 3 / Не могу найти не удалённый эффект
PT153:
Вот так верно будет.
Ред. PT153
» WarCraft 3 / Не могу найти не удалённый эффект
Должен быть включён vJass в JNGP.
» WarCraft 3 / Не могу найти не удалённый эффект