Оч редко, но вот таки снова вылетел
Заметки себе - это с крокодилом и та и другая катка, предположительно все-таки из-за повышения уровня абилы у мёртвого, наверное, там проверка недостаточно правильная

.Q..I.VW.bi...|$ == изменение абилки у мертвого юнита
в логе четко видно ид X82A
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
21
quq_CCCP, в обеих катках с фаталом был крокодил, так что 90%, что из-за крокодила
а у крокодила это самая подозрительная абила
но это что-то очень-очень редкое, в каком бы коде ни было, потому что когда был словлен первый фатал с крокодилом, мной было поставлено 6 ботов-крокодилов и они 5 минут рубились без фатала, и вообще минимум 80% каток с крокодилами проходило без фатала, а точнее, все, кроме двух, вторая только что была
проверок до фига поставлено именно от греха подальше на всякий случай
замечания учту
Вот вся функция целиком на вторую абилу, в которой сильнее всего сомневаюсь:
смотреть сюда
function SkinForFriendsRefresh takes nothing returns nothing
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ: t, u5
local timer t = GetExpiredTimer()
local unit u5=LoadUnitHandle(udg_Hash,GetHandleId(t),2)
local real number = GetUnitArmor(u5)
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ - ЗАКРЫТО
if (u5 == null) then
call PauseTimer (t)
call DestroyTimer (t)
call FlushChildHashtable (udg_Hash, GetHandleId(t))
else
ЕСЛИ БРОНЯ БОЛЬШЕ ДОПУСТИМОГО ЛВЛА - СНИЗИТЬ НОМЕР
if number > GetUnitAbilityLevelSwapped('A28T',u5) * 22 then
set number = GetUnitAbilityLevelSwapped('A28T',u5) * 22
endif
if number > 99 then
set number = 99
endif
ЕСЛИ БРОНЯ БОЛЬШЕ ДОПУСТИМОГО ЛВЛА - СНИЗИТЬ НОМЕР - ЗАКРЫТО.
ДОБАВКА И ДИЗЕЙБЛ СПЕЛЛБУКОВ, ЗАДАНИЕ НУЖНОГО УРОВНЯ СПОСОБНОСТИ, ТОЛЬКО ЕСЛИ ЖИВ!!!
if IsUnitAliveBJ(u5) == true and GetUnitState(u5,UNIT_STATE_LIFE)>1 and IsUnitDeadBJ(u5) == false then
call UnitAddAbility(u5,'A28W')
call SetPlayerAbilityAvailableBJ( false, 'A28W', GetOwningPlayer(u5) )
call UnitMakeAbilityPermanent(u5,true,'A28W')
call UnitMakeAbilityPermanent(u5,true,'A28X')
call SetUnitAbilityLevelSwapped('A28X',u5,R2I(number))
endif
ДОБАВКА И ДИЗЕЙБЛ СПЕЛЛБУКОВ - ЗАКРЫТО.
endif
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ: t, u5
set t = null
set u5 = null
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ - ЗАКРЫТО
endfunction
Может, ещё гетюнитармор не надо в начале считать при объявлении переменных? Она не мемхачная, а старая с хайва и там селфдамаг... может, там если юнита вдруг оказалось, что нет, получается ноль и из-за этого трындец где-то дальше... попробую мб заменить на мемхачную
Я просто пока размышляю
Я по логу хочу причину фатала услышать
У меня два основных предположения - если от вылета из-за повышения уровня абилы у мёртвой боевой единицы, то это точно эта абила (вторая). Если от записи чего-то в память, то это третья.
Третья вот, если кому не лениво ещё и её смотреть:
смотреть сюда
function BlessingOfTheNileAttack takes nothing returns nothing
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ: t, u5, u6
local timer t = CreateTimer()
local unit u5 = GetAttacker()
local unit u6 = GetAttackedUnitBJ()
local integer level = R2I(GetUnitAbilityLevelSwapped('A28U',u5))
local integer i = 0
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ - ЗАКРЫТО
if (u5 !=null) then
if ( GetUnitAbilityLevelSwapped('A28U', u5) > 0 ) and ( GetUnitAbilityLevelSwapped('A290', u5) > 0 ) then
Удаление маркера с атаковавшего
call UnitRemoveAbility(u5,'A290')
Удаление маркера с атаковавшего - закрыто.
ДОБАВКА БРОНИ
call SetUnitBaseArmor(u5, GetUnitBaseArmor(u5) + 0.01 * I2R(level))
ДОБАВКА БРОНИ - ЗАКРЫТО.
call SaveUnitHandle(udg_Hash,GetHandleId(t),2,u5)
call SaveUnitHandle(udg_Hash,GetHandleId(t),1,u6)
call SaveInteger(udg_Hash,GetHandleId(t),3,i)
call SaveInteger(udg_Hash,GetHandleId(t),4,level)
call TimerStart(t,0.25,true,function BlessingOfTheNileAttack2)
else
call PauseTimer(t)
call DestroyTimer(t)
call FlushChildHashtable(udg_Hash, GetHandleId(t))
endif
else
call PauseTimer(t)
call DestroyTimer(t)
call FlushChildHashtable(udg_Hash, GetHandleId(t))
endif
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ: t, u5, u6
set t = null
set u5 = null
set u6 = null
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ - ЗАКРЫТО
endfunction
function BlessingOfTheNileRefresh takes nothing returns nothing
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ: t, u5, u6, p, heroadded, heroaction, enemies
local timer t = GetExpiredTimer()
local unit u5=LoadUnitHandle(udg_Hash,GetHandleId(t),2)
local unit u6
local location p = GetUnitLoc(u5)
local trigger heroadded=LoadTriggerHandle(udg_Hash,GetHandleId(t),20)
local triggeraction heroaction=LoadTriggerActionHandle(udg_Hash,GetHandleId(t),21)
local group enemies=CreateGroup()
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ - ЗАКРЫТО
local integer i = LoadInteger(udg_Hash,GetHandleId(t),3)
set i = i+1
call SaveInteger (udg_Hash,GetHandleId(t),3,i)
Если героя нет, то разрушить таймер, чтобы не крутился и не жрал ресурсы.
if (u5 == null) then
call PauseTimer(t)
call DestroyTimer(t)
call FlushChildHashtable(udg_Hash,GetHandleId(t))
call TriggerRemoveAction(heroadded,heroaction)
call DestroyTrigger(heroadded)
else
call TriggerRemoveAction(heroadded,heroaction)
call DestroyTrigger(heroadded)
set heroadded=CreateTrigger()
set heroaction = TriggerAddAction(heroadded,function BlessingOfTheNileAttack)
set enemies = GetUnitsInRangeOfLocAll(800.00, p)

loop
set u6=FirstOfGroup(enemies)
exitwhen u6==null
call GroupRemoveUnit(enemies,u6)
if ( GetUnitAbilityLevelSwapped('Avul', u6) != 1 ) and ( IsUnitAliveBJ(u6) == true ) and ( IsUnitEnemy(u6,GetOwningPlayer(u5))==true ) then
call TriggerRegisterUnitEvent(heroadded, u6, EVENT_UNIT_ATTACKED)
else
endif
endloop
call DestroyGroup (enemies)
call SaveTriggerHandle(udg_Hash,GetHandleId(t),20,heroadded)
call SaveTriggerActionHandle(udg_Hash,GetHandleId(t),21,heroaction)
endif

call RemoveLocation (p)
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ: t, u5, u6, p, heroadded, heroaction, enemies
set t = null
set u5 = null
set u6 = null
set p = null
set heroadded = null
set heroaction = null
set enemies = null
ВНИМАНИЕ!!! ОБНУЛЯЕМЫЕ ПЕРЕМЕННЫЕ ЗДЕСЬ СПИСКОМ - НОВЫЙ ШАБЛОН СОВЕРШЕНСТВА, ВСЕ ТЕСТКАРТЫ БЕЗ ОНОГО БУДУТ УДАЛЕНЫ - ЗАКРЫТО
endfunction
Кушка простейшая, там фатала в принципе не должно быть, сейчас была перепроверена - ничего подозрительного не вижу...
16
.Q..I.VW.bi...|$ == изменение абилки у мертвого юнита
в логе четко видно ид X82A
Принятый ответ
21
Понятно...
Ну вот он код в первом сообщении, вот A28X абила... Какого панциря при проверке аж тремя функциями
if IsUnitAliveBJ(u5) == true and GetUnitState(u5,UNIT_STATE_LIFE)>1 and IsUnitDeadBJ(u5) == false
игра умудряется его в редком случае видеть НЕ мёртвым?!
Она тут его живого-то с 1 хп за мёртвого должна считать, а получается, что и мёртвого всё-таки иногда (хотя и КРАЙНЕ редко) живым видит.
30
проверка даже излишне осторожная немножко
Прямо поэзия в этих строках есть какая-то. А вообще, "излишне" и "немножко" это взаимоисключающие понятия.
IsUnitAliveBJ(u5) == true and GetUnitState(u5,UNIT_STATE_LIFE)>1 and IsUnitDeadBJ(u5) == false
Три абсолютно идентичные по сути проверки (слегка разные по быстродействию), достаточно одной.

Может, ещё гетюнитармор не надо в начале считать при объявлении переменных? Она не мемхачная, а старая с хайва и там селфдамаг... может, там если юнита вдруг оказалось, что нет, получается ноль и из-за этого трындец где-то дальше... попробую мб заменить на мемхачную
21
Clamp, вот с одной точно жопа будет, потому что уже есть опыт, IsUnitAlive и IsUnitDead точно косые какие-то.
Потому что у меня есть другой герой, Гидралиск, который вселяется в крипа, хайдится и типа входит внутрь него до смерти крипа (можно эту смерть вручную сделать через добавляемую крипу абилку, типа разорвать его изнутри и вылезти).
Там стояла одна проверка.
Так вот в большинстве случаев все было ок, но бывало, что, когда крип умирал, Гидралиск не анхайдился до его разложения (а это полная жопа).
Вот ща там проверка типа такой тройной по-моему и вроде тьфу-тьфу все норм.
Проверка именно поэтому такая хардкорная стоит и здесь, и вот даже её оказалось недостаточно.
Короче, не знаю, в крайнем случае поменяю единицу на цифру чуть побольше (правда, чем больше будет цифра - тем больше уже будет фактическая погрешность в действии способности, но вплоть до 100 хп это будет не сильно страшно), тут трудности в том, что фатал действительно очень редко, так что сложно будет понять, исправлен он окончательно или нет.
/
БД на броню в 2017 и во времена мемхака... как раз с GetUnitArmor от него отказ и произошёл, спасибо, если все через бд делать, так и варкрафт не очень нужен
30

Какого панциря
Сначала все возможные проверки, потом все зависящие от них действия, не наоборот. Кстати:
call UnitAddAbility(u5,'A28W')
call SetPlayerAbilityAvailableBJ( false, 'A28W', GetOwningPlayer(u5) )
call UnitMakeAbilityPermanent(u5,true,'A28W')
call UnitMakeAbilityPermanent(u5,true,'A28X')
call SetUnitAbilityLevelSwapped('A28X',u5,R2I(number))
Весь этот мусор можно вынести в отдельную функцию, намного проще будет дебажить.
И научись, пожалуйста, пользоваться таким построением при постинге:
((код
// тут код
))
21
Clamp, "Сначала все возможные проверки, потом все зависящие от них действия, не наоборот" - а у меня как?
Про функцию - справедливо, ну много чего можно посжимать в функции, да, но это дофига перелопачивать, хотя себя оправдает, ну это ок, но немного другой вопрос.
30
БД на броню в 2017 и во времена мемхака...
"Портируемость" явно не входит в список знакомых тебе понятий. Советую проникнуться ею достаточно глубоко, чтобы не использовать тот или иной недокументированный функционал (это вообще, не только про вц), так как он имеет свойство переставать существовать после багфиксов.

Про "дополнительные" проверки:
//===========================================================================
function IsUnitDeadBJ takes unit whichUnit returns boolean
    return GetUnitState(whichUnit, UNIT_STATE_LIFE) <= 0
endfunction

//===========================================================================
function IsUnitAliveBJ takes unit whichUnit returns boolean
    return not IsUnitDeadBJ(whichUnit)
endfunction

Ну ты понял. =)
21
Clamp, ага, всё понятно, то есть Alive и Dead проверки действительно лишние.
Пока получается так - может существовать фактически мёртвый юнит с количеством жизней, которое игра считает большим 0, и даже большим 1. Иначе не могу объяснить фатал.
Может, у меня там какой-то триггерный хил действует без проверки на мертвяков, хилит мертвяка и... gg.
Хотя вообще большинство функций у меня исключает мертвяков при проверке групп из обрабатываемых единиц, но... могло быть где-то пренебрежение для хила - типа он же мёртвый, какая разница, отхилится или нет, пока не реснется, не важно, а после реса все равно фулл хп будет. Ну вот разница и вылезла. Придётся эти пренебрежения искать.

И поставлю таки наверное вместо 1 конкретно в этой функции хотя бы 25, что ли, это будет не заметно в 99.5% случаев, а фаталы если и не устранит вообще, то сделает их еще меньше (их и ща мало, крокодилом было много норм игр сыграно, ему больше месяца уже и была вот дрочка с 6 ботами-крокодилами, но вот 2 раза таки вылезли).
30
Если совсем по-тупому, то могу предложить создать глобальную группу "все юниты на карте", добавлять туда всех новых юнитов (кроме системных) и по событию смерти удалять из группы, тогда твоя проверка "живости" юнита будет заключаться в проверке нахождения в этой группе, и подобная бага не сможет появиться.

Но это очевидный костыль, хотя и красивый.
21
Clamp, неплохо, подумаю
хотя если для конкретно этого спелла, проще что-то с одним крокодилом замутить, в других случаях пока проблем не замечалось, но все равно стоит иметь в виду такое глобальное решение (как минимум для героев)
ладно, пока, думаю, достаточно, как обновлю код, если еще понадобится - отпишу
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.