а) не жрёт утопленные трупы (при waterlevel>0 трупы монстров почему-то не чекаются);
Рискну предположить, что как-то связано с проверкой по высоте. Может с z-offset стоит поиграться.
Void Weaver:
б) всякий раз когда эти мрази берут труп на прицел, они упорно застревают во всём подряд - в объектах, мобах, друг друге, стенах, мостах и проч.
Надо видеть полный код CorpseChase. Поскольку никаких функций типа ChaseMaster не завезли, есть два путя:
1. Вариант с циклом FaceMaster + Recoil чередующийся с аварийным циклом Wander, здесь параметры наименьшего застревания подбираются только экспериментально. Слишком малого Wander может не хватить, чтобы вывести монстра из застревательной ловушки, слишком большой собьёт наводку. Я, например, в подобных случаях делал вариабельное время аварийного цикла, чтобы долгий Wander включался в одном из десяти, например, случаев.
2. Вариант с Thing_SetGoal и PatrolPoint. Здесь застреваний нет, но изрядное головотрахание с ACS и конфликтующими tid.
Успешных аналогов A_Chase на зскрипте я пока не встречал. В прошлый раз это привело к обнаружению переменной self.movedir, который понимает всего 8 значений (от 0 до 7) и заставляет монстра с CHF_DONTTURN идти строго на одну из восьми сторон света, в произвольном же направлении заставить его двигаться так и не удалось.
Рискну предположить, что как-то связано с проверкой по высоте. Может с z-offset стоит поиграться.
Вероятней всего. Но я же выставил CLOFF_FROMBASE, разве это не означает что уровень ЛОФа должен чекаться с "ног" актора? Т. е. я вполне допускаю что актор не будет чекать утопленника, находясь выше него, "на суше", но спустившись в воду он же будет на одном уровне с трупом, или как?
Честно говоря я вообще не догоняю значения около трети флагов КЛОФа. Бтв, что значит pitch? Что-то связанное с вертикальным углом, да? И чем питч отличается от абсолют питч?
Герр Смертоносец:
Надо видеть полный код CorpseChase. Поскольку никаких функций типа ChaseMaster не завезли, есть два путя:
1. Вариант с циклом FaceMaster + Recoil чередующийся с аварийным циклом Wander, здесь параметры наименьшего застревания подбираются только экспериментально. Слишком малого Wander может не хватить, чтобы вывести монстра из застревательной ловушки, слишком большой собьёт наводку. Я, например, в подобных случаях делал вариабельное время аварийного цикла, чтобы долгий Wander включался в одном из десяти, например, случаев.
Ну по твоим лекалам и сделал:
Скрытый текст:
CorpseChase:
RGWL A 0 A_FaceTracer
RGWL A 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL A 1 A_Recoil (-1)
RGWL A 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL B 0 A_FaceTracer
RGWL B 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL B 1 A_Recoil (-1)
RGWL B 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL C 0 A_FaceTracer
RGWL C 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL C 1 A_Recoil (-1)
RGWL C 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL D 0 A_FaceTracer
RGWL D 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL D 1 A_Recoil (-1)
RGWL D 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL E 0 A_FaceTracer
RGWL E 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL E 1 A_Recoil (-1)
RGWL E 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL F 0 A_FaceTracer
RGWL F 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL F 1 A_Recoil (-1)
RGWL F 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL G 0 A_FaceTracer
RGWL G 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL G 1 A_Recoil (-1)
RGWL G 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL H 0 A_FaceTracer
RGWL H 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL H 1 A_Recoil (-1)
RGWL H 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL I 0 A_FaceTracer
RGWL I 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL I 1 A_Recoil (-1)
RGWL I 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL J 0 A_FaceTracer
RGWL J 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL J 1 A_Recoil (-1)
RGWL J 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL K 0 A_FaceTracer
RGWL K 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL K 1 A_Recoil (-1)
RGWL K 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
RGWL L 0 A_FaceTracer
RGWL L 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL L 1 A_Recoil (-1)
RGWL L 0 A_CheckLOF ("CorpseChaseW", CLOFF_FROMBASE|/* CLOFF_JUMPENEMY|CLOFF_JUMPFRIEND|CLOFF_JUMPNONHOSTILE|*/CLOFF_JUMPOBJECT|CLOFF_MUSTBESOLID|CLOFF_JUMP_ON_MISS|CLOFF_SKIPTARGET/*|CLOFF_ALLOWNULL|CLOFF_NOAIM*/, 80, 0, 0, 0, 0, 0, AAPTR_TRACER, 0)
Loop
CorpseChaseW:
//RGWL A 0 A_FaceTracer
RGWL A 1 A_Wander
//RGWL B 0 A_FaceTracer
RGWL B 1 A_Wander
//RGWL C 0 A_FaceTracer
RGWL C 1 A_Wander
////RGWL D 0 A_FaceTracer
RGWL D 1 A_Wander
//RGWL E 0 A_FaceTracer
RGWL E 1 A_Wander
//RGWL F 0 A_FaceTracer
RGWL F 1 A_Wander
////RGWL G 0 A_FaceTracer
RGWL G 1 A_Wander
//RGWL H 0 A_FaceTracer
RGWL H 1 A_Wander
//RGWL I 0 A_FaceTracer
RGWL I 1 A_Wander
////RGWL J 0 A_FaceTracer
RGWL J 1 A_Wander
//RGWL K 0 A_FaceTracer
RGWL K 1 A_Wander
//RGWL L 0 A_FaceTracer
RGWL L 1 A_Wander
Goto CorpseChase
Закомменченное и коммент-блоченное это то с чем я уже игрался. Чую что косяк мой, причём совершенно тривиальный.
Герр Смертоносец:
Успешных аналогов A_Chase на зскрипте я пока не встречал.
Ну А_Чейс-то вроде только указателем _TARGET лимитирован, а вообще было бы идеально если бы А_Чейс изначально сделали гибким - с возможностью задать поинтер флагами. Эх, мечты, мечты...
Вероятней всего. Но я же выставил CLOFF_FROMBASE, разве это не означает что уровень ЛОФа должен чекаться с "ног" актора? Т. е. я вполне допускаю что актор не будет чекать утопленника, находясь выше него, "на суше", но спустившись в воду он же будет на одном уровне с трупом, или как?
Хрен его знает. Вполне может оказаться, что утопление вместе со спрайтами сдвигает в том числе и линию проверки на несколько пунктов вниз, утыкая на отрицательную высоту. И тогда с точки зрения движка проверка не проходит. Не исключено, что ты нашёл очередной здумовский баг.
Void Weaver:
Честно говоря я вообще не догоняю значения около трети флагов КЛОФа. Бтв, что значит pitch? Что-то связанное с вертикальным углом, да? И чем питч отличается от абсолют питч?
Питч это текущий угол вертикальной наводки "виртуального орудия". Суть в том, что "орудие" это есть у всех и автоматически наводится на таргет. Причём если таргет сдох, угол вполне может некоторое время сохраняться. У функции A_CheckLOF параметр pitch это смещение угла. Грубо говоря, есть таргет, есть наведённое на него орудие, а линию можно прочертить чуть выше и чуть ниже угла наводки.
Проблемы начинаются тогда, когда мы чертим наш вектор не в таргет, а в произвольном направлении. Ведь питч он по-прежнему берёт относительно наводки своего орудия. Поэтому если мы хотим установить угол на 45 градусов к горизонту - нам сначала надо из 45 градусов вычесть собственный угол подъёма орудия.
Void Weaver:
Ну по твоим лекалам и сделал:
Что-то перемудрил ты. Если труп уже "захвачен" и является трасером, то зачем ещё что-то проверять?
CorpseChase:
RGWL A 0 A_JumpIfTracerCloser (30, "CorpseRemove")
RGWL A 0 A_FaceTracer
RGWL K 2 A_Recoil (-1)
RGWL A 0 A_FaceTracer
RGWL K 2 A_Recoil (-1)
RGWL A 0 A_FaceTracer
RGWL K 2 A_Recoil (-1)
A_Jump (200,"CorpseChase") //шанс не перейти на короткий A_Wander
RGWL AAAA 2 A_Wander
A_Jump (200,"CorpseChase") //шанс не перейти на долгий A_Wander
RGWL AAAAAAAAAAAA 2 A_Wander
Goto CorpseChase
Моб будет бежать на труп, иногда совершая произвольную ходьбу и очень иногда долгую произвольную ходьбу, пока не приблизится к трупу на минимальное расстояние. Алсо, с ускорением не переборщи. 1 каждый тик это довольно дофига, а дробные значения оно не понимает.
Хрен его знает. Вполне может оказаться, что утопление вместе со спрайтами сдвигает в том числе и линию проверки на несколько пунктов вниз, утыкая на отрицательную высоту. И тогда с точки зрения движка проверка не проходит. Не исключено, что ты нашёл очередной здумовский баг.
Т. е. если FROMBASE чекает от "пола" а не от "ног"? Хммм, об этом я не подумал.
За питчи - сотни добра, пошёл тестить. ^_^
Герр Смертоносец:
Что-то перемудрил ты. Если труп уже "захвачен" и является трасером, то зачем ещё что-то проверять?
Эээ, ну как что? Разве актор постоянно глядя FaceTracer'ом в одну точку поймёт что Рекоил уткнул болезного в препятствие? Попробую но чую что будет неладное.
Герр Смертоносец:
Моб будет бежать на труп, иногда совершая произвольную ходьбу и очень иногда долгую произвольную ходьбу, пока не приблизится к трупу на минимальное расстояние. Алсо, с ускорением не переборщи. 1 каждый тик это довольно дофига, а дробные значения оно не понимает.
Я хз рубал ли ты во вторую Ди или нет, но для этих обжор присутствие трупа было приоритетом №1, за исключением цели в пределах мили. Причём они особо не разгуливали а безотлагательно шли к ближайшему трупу прямой наводкой, так что я не заинтересован чтобы они особо разгуливали. Ускорение вроде уже подобрал, тем более в шутере они должны быть значительно шустрее чем в оригинале, иначе рискуют стать просто митшилдом.
Ну в любом случае я до кучи прописал им по-дефолту вампиризм и %-ый хил с жрачки.
Эээ, ну как что? Разве актор постоянно глядя FaceTracer'ом в одну точку поймёт что Рекоил уткнул болезного в препятствие?
Абсолютно не обязательно.
Пример 1: препятствие это яма.
Пример 2: препятствие имеет щель, недостаточную для прохождения актора.
Тут, увы, от всех случаев не перестрахуешься. А сделаешь костыль от ям - получишь косяк на Zbridge, например. Так что в таких конструкциях как-то практичней полагаться на вероятностные вещи.
var fixed user_speed;
states
{
spawn:
TNT1 A 1 {if(user_speed == 0) {user_speed = -0.3} }//если вдруг забыл актеру прописать в аргументах скорость, ставим по умолчанию.
TNT1 A 1 A_Recoil(args[0]) //в аргументы число с точкой кажется не передается по моему, можно тогда A_Recoil(user_speed)
}
так удобно потом в gzdb(если zzyzx пофиксил) задавать скорость, да и в ацс скриптах удобно через SetUserVariable задавать скорость.
Пофиксил waterlevel check, действительно изи - убрал ФРОМБЭЙЗ + снизил высоту. А вот с чеком препятствий чё-т не взлетает.
Герр Смертоносец:
Void Weaver:
Разве актор постоянно глядя FaceTracer'ом в одну точку поймёт что Рекоил уткнул болезного в препятствие?
Абсолютно не обязательно.
Пример 1: препятствие это яма.
Пример 2: препятствие имеет щель, недостаточную для прохождения актора.
Тут, увы, от всех случаев не перестрахуешься. А сделаешь костыль от ям - получишь косяк на Zbridge, например. Так что в таких конструкциях как-то практичней полагаться на вероятностные вещи.
Да, видимо АИ ещё пилить и пилить - в м1e1 Еретика\Дума2 как раз второй случай и проявляется, плюс вскрылась ещё одна частность чека недосягаемых трупов - чекаются трупы которые лежат значительно выше актора. Кароч, без "умного" джампа из стэйта трупочейса не обойтись, так бы я приказал им забыть недосягаемый труп. То есть обойтись-то можно, но в определенных ситуациях тупить будут страшно.
чекаются трупы которые лежат значительно выше актора
Иногда у функций уже есть доп. параметры.. надо просто почитать все их возможности в звики. Когда знаешь на что способна та или иная функция, сможешь реализовать раз в 100 больше и быстрее
A_FaceTracer [(float max_turn [, float max_pitch [, float ang_offset [, float pitch_offset [, int flags [, float z_add]]]]])]
z_add: Offsets the z position distance of the tracer by this number. Unlike pitch_offset, this takes into account how far away the actor is at all times.
Тут немного другое - чек происходит до всяких Фэйсов. Первым CLOF, который и делает труп трэйсером. Я конечно попробую, но чую что тогда актор просто "зависнет" - _TRACER от CLOF получил, но никак на него не реагирует, а значит и не перейдёт к дальнейшим действиям.
Т. е. логичнее было бы задавать Z в ФэйсТаргете, до установки _ТРЭЙСЕРа из КЛОФа, но тогда актор не будет стрелять в игрока и других акторов которые окажутся за пределами величины. Возможно ошибаюсь, но подозреваю что тут по-прежнему загвоздка в ювелирной настройке первого КЛОФа.
Тут немного другое - чек происходит до всяких Фэйсов. Первым CLOF, который и делает труп трэйсером. Я конечно попробую, но чую что тогда актор просто "зависнет" - _TRACER от CLOF получил, но никак на него не реагирует, а значит и не перейдёт к дальнейшим действиям.
А у https://zdoom.org/wiki/A_CheckLOF смотрел, нет ли там возможности ограничить поиск по высоте ?
Я кажется никогда не использовал эту функцию, потому просто мои предположения что вот это может помочь?
offsetheight: Offset the line of fire's point of origin by this value. The base height depends on flags; hitscan emulation (around the middle) by default. When pitch is determined by aiming for target, aim is adjusted to correct for this offset. Default is 0.
Это первоначальный вариант, offsetheight сейчас итак -25 - это как раз пофиксило чек "утопших". С питчами уже игрался, сейчас пробую комбинировать флаги отвечающие за прицеливание.
Но опять таки, меня больше напрягает неработоспособность второго КЛОФа в стэйте трупочейса. Если бы они работали, то можно было бы заставить через _RearrangPointers "забыть" недоступный ТРЭЙСЕР.
Как можно задать A_JumpIfInventory "наоборот"? Ну чтобы джамп совершался при отсутствии энного ко-ва итема? Пробовал такой костыль:
See4:
TNT1 A 0 A_SpawnItemEx("FrenzyTimer4",0,0,0,0,0,0,0,SXF_SETMASTER) //Таймер выдаёт "Frenzy4"
See4Real:
MLWL A 0 A_JumpIfInventory ("Frenzy4",1,2) //Если "Frenzy4" е, прыг в ФэйсТрг
MLWL A 0 A_Jump (256, "See")
MLWL A 1 A_FaceTarget
MLWL ABCDEFGH 1 A_Chase ("Melee4")
Loop
но он работает через жёпп - в 50% случаев таки прыгает в See, несмотря на то что итем уже есть, хз с чем это связано.
Мне же нужно чтобы в "See" прыгало только при Frenzy4 итем = 0, офк проверка должна быть цикличной, внутри "See4Real"
но он работает через жёпп - в 50% случаев таки прыгает в See, несмотря на то что итем уже есть, хз с чем это связано.
Мне же нужно чтобы в "See" прыгало только при Frenzy4 итем = 0, офк проверка должна быть цикличной, внутри "See4Real"
See4:
TNT1 A 1 A_SpawnItemEx("FrenzyTimer4",0,0,0,0,0,0,0,SXF_SETMASTER) //Если что не так, пробуй ставить минимум 1 тик, когда надо спавнить.
See4Real:
MLWL A 0 A_JumpIf(CountInv("Frenzy4") == 0, "See") //Если нет вещи Frenzy4, прыгает в стейт see.
MLWL A 1 A_FaceTarget
MLWL ABCDEFGH 1 A_Chase ("Melee4")
Loop