Welcome to U.A.C. [O.S.A.]
login / register 
Status: Guest
Архивы форума | iddqd.ru
Wolf 3D
ПравилаПравила ПоискПоиск
18+
Тема для новичков. Вопросы по маппингу/моддингу - любые!-2 Пред.  1, 2, 3 ... 61, 62, 63 ... 67, 68, 69  След.
   Список разделов - Местечко мапперов и моддеров - Тема для новичков. Вопросы по маппингу/моддингу - любые!-2Ответить
АвторСообщение
JSO x
- 2nd Lieutenant -
Next rank: = 2nd Lieutenant = after 104 points
1336

Doom Rate: 2.26

Posts quality: +726
Ссылка на пост №1221 Отправлено: 23.01.24 17:24:45
RastaManGames пишет:
Как минимум, это частично убьёт совместимость с модами, т.к. в монстрятниках у человека будут заменённые манкубусы и твои "фальшивки" с ванильными спрайтами.

Почему? В фальшивке ведь тоже ванильные спрайты использоваться будут. Насколько понял, имелась в виду полная копия манкубуса за исключением того, что это новый "класс", а не манкубус.

Мой теоретический вариант — почти то же самое, но только с переиспользованием стандартных ресурсов и стейтов. Возможно, таким образом даже в оригинальном Doom реально создать два вида манкубусов... Да, оба вызывают "A_BossDeath()", но обрабатываться вызов будет только у настоящего.

Рейтинг сообщения: +2, отметил(и): RastaManGames, Michael63
2 7 1
RastaManGames
- 2nd Lieutenant -
Next rank: = 2nd Lieutenant = after 150 points
1290

Doom Rate: 2.02

Posts quality: +596
Ссылка на пост №1222 Отправлено: 23.01.24 17:54:09
JSO x пишет:
Почему? В фальшивке ведь тоже ванильные спрайты использоваться будут.

Я не уточнил, что монстрятник предполагает замену ванильных манкубусов путём реплейсера.
Один чёрт итог будет таков, что среди новых и крутых монстров будут "фальшивки".

Рейтинг сообщения: +1, отметил(и): JSO x
1 2 1
Герр Смертоносец
- Warrant Officer -
Next rank: = Warrant Officer = after 97 points
1043

Doom Rate: 1.38

Posts quality: +855
Ссылка на пост №1223 Отправлено: 23.01.24 20:57:20
Michael63 пишет:
Можно ли в формате Boom + Umapinfo + DehExtra сделать так, чтобы какое-то действие типа BossAction выполнялось при убийстве не всех манкубусов на уровне, а только определённой группы манкубусов? Или определённого количества манкубусов, но не всех на уровне?

Чисто теоретически для ванили возможен трюк с поднятием пола в секторе, где находится монстр. Поднимать пол чем-то вроде Floor_RaiseByValue, при этом чтобы фрагмент поднимающегося пола был в жёсткой связке с другим фрагментом, создающим "мостик" для вуду-куклы/телепортируемого монстра. Вроде бы для жёсткой связки надо что-то там вручную прописывать в linedefs/sectors, но эту тему я знаю плохо. Смысл в том, что пока монстр живой - он блокирует поднятие пола, и сам фрагмент желательно делать невидимым и максимально тонким, но здесь уже возможны нюансы. Актуально для монстров, запертых в клетках. Для Boom возможна чуть более продвинутая схема, чтобы какая-то "дверь" в секторе с монстром постоянно пыталась закрыться, и если ей это хоть раз удалось - вудукукла в конвейере прекращала бы циклически активировать механизм, блокирующий путь другой вудукукле, и уже вторая вудукукла открыла бы эту дверь навсегда. В этом случае всю эту махинацию можно было бы относительно беспалевно спрятать в секторе, где бегает игрок.

Но это такие многоэтажные костыли, что проще сделать отдельного манкубуса с отдельным экшеном/ACS_Execute после смерти, и всякие любители BrutalDoom пусть идут к дьяволу.

Есть ещё третий путь для Z-портов. Сделать декорейтом особый невидимый актор, с A_CheckProximity с флагом CPXF_COUNTDEAD либо CPXF_DEADONLY, который сидит в секторе с монстром и активирует скрипт, не досчитавшись живого монстра нужного класса. Это сработает и с модами, но лишь с теми из них, которые наделяют манкубуса иными свойствами, но не заменяют его актором с другим именем. Однако если этот актор будет связан с монстром пойнтером (например, он же его и спавнит), то можно вместо A_CheckProximity использовать A_JumpIfHealthLower с указанием пойнтера, и этот вариант уже совместим с большинством модов.

Michael63 пишет:
Мне пришёл в голову извращённый вариант - сделать как бы копию манкубуса с помощью DehExtra. Но не знаю, не придерутся ли к этому на idgames.

А с какого лешего им до этого придираться? У них религиозный запрет на модификацию монстров?
5
Michael63
Lieutenant Colonel
Next rank: - Colonel - after 176 points
3864

Doom Rate: 2

Posts quality: +849
Ссылка на пост №1224 Отправлено: 23.01.24 21:08:25
Герр Смертоносец пишет:
Смысл в том, что пока монстр живой - он блокирует поднятие пола

Да, это я уже придумал независимо. :cool: Но проблема в том, что я замыслил уровень, где начало в некотором роде напоминает Dead Simple, хотя и с совсем другим сеттингом, и там высокие потолки, а манкубусы и пауки должны свободно перемещаться. А после этой локации в том же уровне потом будет ещё одна с пауками и манкубусами. Впрочем, лучше я как-то поменяю свою задумку, чтобы второй локации не было.

Герр Смертоносец пишет:
А с какого лешего им до этого придираться? У них религиозный запрет на модификацию монстров?

Там при использовании немодифицированных ресурсов из оригинальных IWAD-ов (точнее, при добавлении немодифицированных ресурсов в свой вад) иногда отфутболивают на этапе публикации в idgames. Можно, конечно, дубликатам монстров нарисовать глаза другого цвета, и тогда ресурсы будут модифицированными. Но это выглядит онанизмом.
1 1 2
SilverMiner
= Master Sergeant =
Next rank: - Sergeant Major - after 56 points
474

Doom Rate: 2.23

Posts quality: +191
Ссылка на пост №1225 Отправлено: 23.01.24 21:21:26
Копия манкубуса может быть чисто предмет со всеми параметрами, скопированными у оригинального манкубуса. В Whacked 4 это просто копирование манкубуса куда-нить на свободный слот. А дальше ему надо поредачить стейты смерти, и там keendie заюзать с тэгом любым, куклами на карте выпрямить если надо и будет хорошо
1 1
JSO x
- 2nd Lieutenant -
Next rank: = 2nd Lieutenant = after 104 points
1336

Doom Rate: 2.26

Posts quality: +726
Ссылка на пост №1226 Отправлено: 24.01.24 00:08:00
RastaManGames пишет:
Я не уточнил, что монстрятник предполагает замену ванильных манкубусов путём реплейсера.
Один чёрт итог будет таков, что среди новых и крутых монстров будут "фальшивки".

Верно-верно, вскоре после отправки понял, что имелись в виду аномалии в поведении, а не в визуальном отображении. Но всё равно, при полной копии "класса" актора такой эффект гарантирован; а вот при создании на DeHackEd чего-то вроде "Spawn: goto Fatso::Spawn" я в результате не уверен, хотя и сдаётся мне, что в итоге выйдет баш на баш... Плохо, когда один стандарт накладывается на другой.

Герр Смертоносец пишет:
Смысл в том, что пока монстр живой - он блокирует поднятие пола, и сам фрагмент желательно делать невидимым и максимально тонким, но здесь уже возможны нюансы. Актуально для монстров, запертых в клетках. Для Boom возможна чуть более продвинутая схема, чтобы какая-то "дверь" в секторе с монстром постоянно пыталась закрыться, и если ей это хоть раз удалось - вудукукла в конвейере прекращала бы циклически активировать механизм, блокирующий путь другой вудукукле, и уже вторая вудукукла открыла бы эту дверь навсегда.

Вообще, если верно понял суть, это идея неплохая. Пара модификаций: микросектор лифта, которому живой манкубус не даёт подняться, соединён с сектором, поднимающим вуду-куклу; как только манкубус умирает — лифт спокойно поднимается и кукла сталкивается на нужную активирующую линию.

Герр Смертоносец пишет:
Есть ещё третий путь для Z-портов. Сделать декорейтом особый невидимый актор, с A_CheckProximity с флагом CPXF_COUNTDEAD либо CPXF_DEADONLY, который сидит в секторе с монстром и активирует скрипт, не досчитавшись живого монстра нужного класса.

Это всё обходится, через "Actor.GetReplacee()" и, например, "WorldThingDied()". Но — на ZScript, который, равно как и ACS/Decorate, в RDC2024 использовать не предполагается совершенно.

SilverMiner пишет:
Копия манкубуса может быть чисто предмет со всеми параметрами, скопированными у оригинального манкубуса. В Whacked 4 это просто копирование манкубуса куда-нить на свободный слот. А дальше ему надо поредачить стейты смерти, и там keendie заюзать с тэгом любым, куклами на карте выпрямить если надо и будет хорошо

Остаётся проблема с модификациями, о которой говорил RastaManGames.

Рейтинг сообщения: +1, отметил(и): RastaManGames
2 7 1
Michael63
Lieutenant Colonel
Next rank: - Colonel - after 176 points
3864

Doom Rate: 2

Posts quality: +849
Ссылка на пост №1227 Отправлено: 24.01.24 00:17:41
JSO x пишет:
Вообще, если верно понял суть, это идея неплохая. Пара модификаций: микросектор лифта, которому живой манкубус не даёт подняться, соединён с сектором, поднимающим вуду-куклу; как только манкубус умирает — лифт спокойно поднимается и кукла сталкивается на нужную активирующую линию.

На всякий случай учитывай, что если разность между ростом монстра и ростом игрока не очень большая, то это не сработает, т.к. кукла игрока заедет на более высокий пол как на ступеньку. "Плавали, знаем" (из опыта с Technohell Tower*). У меня есть идея, как это обойти, но всё равно это всё к чёрту, если манкубус (или несколько) должен (должны) ходить по сектору большой площади и большой высоты, в котором всякие большие искусственные навороты не должны быть видимы.

*Хотя, строго говоря, там я это пробовал не с куклой, а с самим игроком. Но один фиг, это не решит ту задачу, о которой говорил я.
1 1 2
Герр Смертоносец
- Warrant Officer -
Next rank: = Warrant Officer = after 97 points
1043

Doom Rate: 1.38

Posts quality: +855
Ссылка на пост №1228 Отправлено: 24.01.24 00:35:54
Michael63 пишет:
Там при использовании немодифицированных ресурсов из оригинальных IWAD-ов (точнее, при добавлении немодифицированных ресурсов в свой вад) иногда отфутболивают на этапе публикации в idgames. Можно, конечно, дубликатам монстров нарисовать глаза другого цвета, и тогда ресурсы будут модифицированными. Но это выглядит онанизмом.

А зачем тебе добавлять немодифицированные спрайты манкубуса? Тебе надо добавить модифицированный код манкубуса (который во-первых много лет в общественном достоянии, во-вторых к IWAD-ам не имеет отношения). Если у тебя манкубус должен польку тенцевать - тебе придётся добавить модифицированные спрайты манкубуса. Единственная причина, при которой тебе вообще могут понадобиться немодифицированные спрайты из оригинальных IWADов - это если ты хочешь засунуть думовского манкубуса в мод для Heretic или куда-то на другой движок вообще.
5
Michael63
Lieutenant Colonel
Next rank: - Colonel - after 176 points
3864

Doom Rate: 2

Posts quality: +849
Ссылка на пост №1229 Отправлено: 24.01.24 00:44:40
Герр Смертоносец пишет:
А зачем тебе добавлять немодифицированные спрайты манкубуса?

Может быть, ты прав, что их нет необходимости добавлять. Я просто не знаю. Человек вообще из другой сферы, и довольно многое осваиваю "по ходу пьесы". Но когда-то в детстве придумывал уровни и рисовал на бумаге, было интересно, так что может и в этом году что-нибудь сделаю.
1 1 2
Герр Смертоносец
- Warrant Officer -
Next rank: = Warrant Officer = after 97 points
1043

Doom Rate: 1.38

Posts quality: +855
Ссылка на пост №1230 Отправлено: 24.01.24 01:18:27
JSO x пишет:
Вообще, если верно понял суть, это идея неплохая. Пара модификаций: микросектор лифта, которому живой манкубус не даёт подняться, соединён с сектором, поднимающим вуду-куклу; как только манкубус умирает — лифт спокойно поднимается и кукла сталкивается на нужную активирующую линию.

Именно так. Здесь вопрос в том, как сделать это максимально незаметным для игрока. Возможно, имеет смысл не поднимать лифт, а опускать потолок, причём не в ноль, а лишь до какой-то критической высоты, слегка превышающей высоту игрока. Это не сможет заблокировать обычный закольцованный вуду-конвейер, но сможет заблокировать вуду-конвейер-лестницу с перепадом высот.

Блокировка же закольцованного вуду-конвейера может разблокировать второй вуду-конвейер по следующей схеме. Перед второй вудукуклой стоит дверь из двух половинок с двумя разными сектор-номерами. В процессе закольцованного движения первого конвейера они по очереди то закрываются, то открываются (таким образом, пока закрыта хотя бы одна половинка - вторая вудукукла стоит на месте и не блокирует открывшуюся половинку). Если в закольцованном конвейере возникает задержка - второй конвейер открывается полностью.

JSO x пишет:
Это всё обходится, через "Actor.GetReplacee()" и, например, "WorldThingDied()". Но — на ZScript, который, равно как и ACS/Decorate, в RDC2024 использовать не предполагается совершенно.

В любом случае, если предполагается использовать хотя бы декорейт - можно придумать стопицот способов установить поинтерные взаимоотношения монстра и следящего за ним объекта. Спавны, A_CheckLOF, выстреливание в монстра снарядом с последующей очисткой ему target-поинтера и.т.п.

Если не предполагается даже декорейт - всё становится значительно сложнее. К примеру, можно высотроить карту так, чтобы нужный монстр выстрелил в пинки, спрятанного в специальном коридоре, и пинки на него бы обиделся. Обиженный пинки будет бежать к своей цели и не будет бежать в противоположном направлении - где стоит телепорт. Когда монстр убит - движения пинки станут более хаотичными, и в какой-то момент он зайдёт в телепорт и заблокирует конвейер. Ширина пинки больше ширины игрока, поэтому достаточно телепортировать его в расширенное место, откуда он никуда перейти не сможет. Чтобы пинки не поел вуду-куклу - придётся дополнительно спереди и сзади защитить её бочками, а телефрагнуть в ванили монстры никого не могут и просто не телепортятся в занятый сектор. Эта схема представляется наиболее беспалевной, но требует мапперского искусства - как спрятать пинки и заставить монстра сагрить его на себя.

Рейтинг сообщения: +1, отметил(и): JSO x
5
Дмитрий С.
- Warrant Officer -
Next rank: = Warrant Officer = after 76 points
1064

Doom Rate: 3.94

Posts quality: +171
Ссылка на пост №1231 Отправлено: 27.01.24 23:37:38
Нашел в сети онлайн-книжку "Проектирование виртуальных миров. Теория и практика дизайна уровней" Правда, она не про Дум, а про современные игры, но тем не менее какие-то вещи могут быть интересны и местной аудитории.
1 1 12
theleo_ua
= Colonel =
Next rank: - Commissar - after 88 points
4802

Doom Rate: 1.8

Posts quality: +1033
Ссылка на пост №1232 Отправлено: 29.01.24 05:22:42
Приветствую, уважаемые господа

Возникла проблема которую пока не представляю, как фиксить, но более того, ее даже объяснить не так просто, так что начну

Для начала, распишу как оно должно работать:

Скрытый текст:



в хексене есть такой предмет - banishment device или баниш. Он телепортит монстров в случайный дезматч спавн. В оригинальном хексене им легко засофтлочить игру, телепортируя тех монстров, которых по задумке автора надо убивать, после чего по скрипту откроется дверь например (а если забанишить, то не откроется и ты ничего не сможешь сделать). Для этого, я в своем моде придумал callback device - предмет, который всех забанишенных (и которые все еще живы) телепортит назад в точку юза предмета.

Выглядит это примерно так: https://www.youtube.com/watch?v=QDaKRUMmimw

Скрытый текст:



Т.е. в ролике видно, как я телепортирую серпентов банишем за пределы комнаты, потом моим девайсом телепортирую их назад, и спокойно их убиваю, открывая стенку к бишопам (по скрипту авторов), тем самым игра не софтлочится, что дает мне свободу применения баниша когда хочу и на кого хочу.


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

Мне сложно это описать словами, поэтому кину примеры таймингов в видео, как это работает:

https://www.youtube.com/watch?v=lUlMqIGGkJ4&list=PL5QwAqOy7WAC8tbrLIP16emEYWlVVWAJH&index=43&t=0h19m30s#t=0h19m30s

смотреть с 0:19:30 по 0:19:57 и с 0:23:07 по 0:23:12

здесь видно как работает баниш когда одним выстрелом телепортишь сразу нескольких и как телепортится только один. И обратите внимание, что по внешнему виду снаряда хрен определишь, сколько их там летит

также стоит отметить, что если бы я на 0:19:30 сохранился, и попробовал после загрузки поюзать баниш много раз, то некоторые попытки телепортили бы только одного монстра за выстрел, а некоторые больше одного

т.е. с этим понятно, сам снаряд баниша "не простой, а золотой (с)", т.е. замороченный



Теперь в чем проблема:

Скрытый текст:



недавний стрим показал, что мой коллбек девайс телепортит назад не всех монстров. И связано это с тем, что именно на момент контакта баниша с монстром, мой скрипт иногда срабатывает, а иногда нет (вижу я это по debug строке текста "monster count = X", которая выводится на экран при контакте баниша с монстром). Соответственно, я хочу понять, почему так происходит, и как сделать, чтобы каждое попадание баниша активировало мой скрипт (в результате чего, каждый забаненный монстр телепортанется назад потом при активации callback device).

Вот как выглядит баг на стриме: https://clips.twitch.tv/LitigiousRelentlessManateeWutFace-E35zNoD-xHW9Be76 (телепорт есть, а скрипт не срабатывает)




Теперь, когда проблема расписана, объясню как это работает технически:

Скрытый текст:



1) в зскрипте переопределен баниш. При контакте с монстром, он запускает для него ACS скрипт
2) данный ACS периодически раз в X тиков чекает, а не надо ли телепортить монстра назад (проверяя переменную)
3) при применении call back device, переменная "надо телепортить назад" активируется
4) соответственно, когда ACS замечает значение переменной "вкл", то телепортит монстра назад

Т.е., как я понимаю, проблема скорее всего кроется именно в пункте 1 - я где-то напортачил в зскрипте и ACS, и из-за этого часть монстров не получает свой скрипт. Предположу, что проблема связана именно с тем, что проджектайлов баниша может выпуститься разное количество



теперь кидаю сам код моего мода:

Скрытый текст:



ZSCRIPT (переопределенный баниш): https://pastebin.com/raw/TQ4XzVLM

вот что изменено:

Скрытый текст:


// Send all monsters to deathmatch spots
P_TeleportToDeathmatchStarts_HHMIX (target);

//ACS_NamedExecuteWithResult("Test_Banish");
//mobj.ACS_ScriptCall("SomeScript");
target.ACS_ScriptCall("BF_AttachToMonster");



ACS (скрипт который аттачится к монстру при контакте и остальные скрипты): https://pastebin.com/raw/LNGJ6FWA

DECORATE (здесь вряд-ли будет что-то важное для отлова бага, но на всякий случай скинул): https://pastebin.com/raw/Chwi7aLc

BF это так называется callback device (сокращение от Banish Fix), надо будет потом поменять, чтобы не конфузило



Перед тем, как будете отвечать, уточню ряд моментов:

1) гздум. Версия гздума актуальная, т.е. 4.11.3 либо более новая, если она выйдет на момент ответа
2) у меня нет цели "делать строго на ACS": если ваше решение будет "уйти от ACS и сделать все на зскрипте" - меня оно вполне устроит, главное чтобы я понял, как это сделать
3) я не планировал юзать зчекер в ближайшее время, но конкретно этот случай мне показался таким, что именно он поможет в отлове бага, так что я скорее всего попробую и его (подробнее об этом в теме зчекера напишу)
3 1
JSO x
- 2nd Lieutenant -
Next rank: = 2nd Lieutenant = after 104 points
1336

Doom Rate: 2.26

Posts quality: +726
Ссылка на пост №1233 Отправлено: 31.01.24 22:01:54
theleo_ua пишет:
В оригинальном хексене им легко засофтлочить игру, телепортируя тех монстров, которых по задумке автора надо убивать, после чего по скрипту откроется дверь например (а если забанишить, то не откроется и ты ничего не сможешь сделать)

Судя по коду актора "TelOtherFX1_Leo_ZS_Placeholder::DoSpecialDamage()" (и его оригинальному прототипу из gzdoom.pk3), у всех монстров поле "special" перед телепортацией исполняется автоматически, а сам монстр его лишается:
// If death action, run it upon teleport
if (target.bIsMonster && target.special)
{
    target.RemoveFromHash ();
    Actor caller = level.ActOwnSpecial? target : self.target;
    caller.A_CallSpecial(target.special, target.args[0], target.args[1], target.args[2], target.args[3], target.args[4]);
    target.special = 0;
}



theleo_ua пишет:
Так вот, с банишем они тоже заморочились: когда ты применяешь баниш, то от тебя вылетает не строго один снаряд, а рандомное их количество (или не рандомное, но ощущается как рандомное). По итогу происходит так, что одним банишем ты можешь телепортануть как одного так и 5 монстров например, и зависит это от кучи нюансов, так как проджектайлы там особенные

Не, вылетает как раз один. Но через несколько тактов начинает создавать свои ослабленные копии под названиями "TelOtherFX2".."TelOtherFX5" — они меньше живут и только телепортируют, без порождения дополнительных акторов. Так что при благоприятном исходе (== "при достаточном удалении от точки вылета") этот поезд из снарядов может задеть до семи-десяти монстров, а в некоторых случаях и более.



theleo_ua пишет:
Т.е., как я понимаю, проблема скорее всего кроется именно в пункте 1 - я где-то напортачил в зскрипте и ACS, и из-за этого часть монстров не получает свой скрипт.

Возможно, стоит использовать "ACS_NamedExecuteAlways()". "ACS_ScriptCall()" вызывает "ACS_NamedExecuteWithResult()" (не-always вариант), так что скрипты могут и не запуститься.


theleo_ua пишет:
2) у меня нет цели "делать строго на ACS": если ваше решение будет "уйти от ACS и сделать все на зскрипте" - меня оно вполне устроит, главное чтобы я понял, как это сделать

С учётом первого абзаца это точно целесообразно? Если "да", могу предложить следующий вариант:
1. В ZScript, в хранилище глобальных переменных, создать динамический массив всех сохраняемых монстров.
2. При работе Callback Device напрямую обращаться к глобальным переменным, сразу удаляя возвращённого противника из массива.
Скрытый текст:

class GlobalVars: Thinker {
    Array<Actor> actorsToReturn;

    static GlobalVars Get() { ... } // См. ссылку в пункте 1.

    // Убираем всех более не нужных акторов:
    void ActorsToReturnCollectGarbage() {
        for ( int i = 0; i < actorsToReturn.Size(); i++ ) {
            if ( actorsToReturn[ i ] == NULL || actorsToReturn[ i ].health <= 0 )
                actorsToReturn.Delete( i-- );
        }
    } // of void ActorsToReturn() {}

    void ActorsToReturnAdd( Actor a ) {
        actorsToReturn.Push( a );
    }

    // Возвращаем случайного актора, удаляя его из списка:
    Actor ActorsToReturnRandomPop() {
        int arrsize = actorsToReturn.Size();

        if ( arrsize == 0 )
            return NULL;

        int rndindex = Random( 0, arrsize - 1 );
        Actor outactor = actorsToReturn[ rndindex ];
        actorsToReturn.Delete( rndindex );

        return outactor;
    } // of Actor ActorsToReturnRandomPop() {}

} // of class GlobalVars: Thinker {}


class CallbackDevicePlatform: Actor {
    // <...>

    void TeleportBack() {
        GlobalVars globals = GlobalVars.Get();

        globals.ActorsToReturnCollectGarbage();
        Actor ret = globals.ActorsToReturnRandomPop();

        if ( ret ) {
            // Если акторы ещё есть:
            ret.SetOrigin( pos, false );
            SetStateLabel( "TeleportFlash" );

        } else {
            // Если акторы закончились:
            SetStateLabel( "Finish" );
        }
    } // of void TeleportBack() {}

} // of class CallbackDevicePlatform: Actor {}



P. S.: часть кода с PasteBin так и не загрузилась, Cloudflare говорит "Error code 522: Connection timed out" — так что местами восстанавливал картину по косвенным данным.

Рейтинг сообщения: +1, отметил(и): theleo_ua
2 7 1
theleo_ua
= Colonel =
Next rank: - Commissar - after 88 points
4802

Doom Rate: 1.8

Posts quality: +1033
Ссылка на пост №1234 Отправлено: 01.02.24 01:14:25
JSO x пишет:
у всех монстров поле "special" перед телепортацией исполняется автоматически, а сам монстр его лишается:


Да, я в курсе, но там есть нюанс: этот special не всегда помогает

Примеры:

1) Deatkkings, карта hxvisit 20 (там где последние боссы)

На ней, если банишить плеербоссов, то сразу активируется скрипт как будто они умерли, т.е. всё будет работать


2) Оригинал, карта gibbet (hxvisit 22)

Там скрипт такой: "если на карте 3 серпента, то открыть двери". Т.е. скрипт не проверяет special, и когда ты банишишь, то серпентов все еще останется 4 и скрипт не сработает


3) мой последний стрим - это маппак scourge of viscerus, первая карта:

https://www.youtube.com/watch?v=TscNxpj6sZQ&t=5h51m12s#t=5h51m12s (смотреть с 5:51:12 по 5:51:35)

https://www.youtube.com/watch?v=TscNxpj6sZQ&t=5h53m20s#t=5h53m20s (смотреть с 5:53:20 по 5:53:39)

На самом деле можно первую ссылку смотреть сразу с 5:51:12 по 5:53:39, но тогда будешь наблюдать 2минутный расстрел монстров, так что лучше увидеть по первому таймингу как я их забанишил, и по второму таймингу результат (скрипт сломан, колонна с кнопкой в центре не появилась), а чуть дальше видно, как я гружу сейв, прохожу то же место без банишей, и после убийства серпентов скрипт срабатывает как надо


Так что special помогает, но не всегда (если бы всегда помогал, то callback device не нужен был бы)

JSO x пишет:
Возможно, стоит использовать "ACS_NamedExecuteAlways()". "ACS_ScriptCall()" вызывает "ACS_NamedExecuteWithResult()" (не-always вариант), так что скрипты могут и не запуститься.


Я попробую, но такой вопрос: а по какой логике WithResult может не запуститься? Что конкретно ему мешает запускаться? Мне всегда казалось, что разница там только в "один дает результат, а второй нет", но запускаются всегда оба варианта

JSO x пишет:
С учётом первого абзаца это точно целесообразно?


не понял, о каком первом абзаце речь, процитируй пожалуйста

про целесообразность - меня устраивает вариант полного перехода на зскрипт (рано или поздно все равно придется это делать для всех модов), другое дело что мне придется разбираться, как этот код работает и как работает зскрипт в принципе (в этом контексте), чтобы смочь его корректно применить и оно работало

JSO x пишет:
1. В ZScript, в хранилище глобальных переменных, создать динамический массив всех сохраняемых монстров.
2. При работе Callback Device напрямую обращаться к глобальным переменным, сразу удаляя возвращённого противника из массива.
Скрытый текст:


руки дойдут, попробую разобраться

JSO x пишет:
P. S.: часть кода с PasteBin так и не загрузилась, Cloudflare говорит "Error code 522: Connection timed out" — так что местами восстанавливал картину по косвенным данным.


а куда выкладывать, чтобы у тебя гарантированно работало? Ну кроме "под спойлер на форум", так как может заглючить из-за спец символов
3 1
JSO x
- 2nd Lieutenant -
Next rank: = 2nd Lieutenant = after 104 points
1336

Doom Rate: 2.26

Posts quality: +726
Ссылка на пост №1235 Отправлено: 01.02.24 16:30:29
theleo_ua пишет:
Там скрипт такой: "если на карте 3 серпента, то открыть двери". Т.е. скрипт не проверяет special, и когда ты банишишь, то серпентов все еще останется 4 и скрипт не сработает

А. Так это проблема кривого ACS-скрипта, а не артефакта. Мы с человеком именно из-за этого бага когда-то совместное прохождение Hexen бросили, так как последним выстрелом убили сразу двух змей; нужные двери не открылись, и куда было дальше идти, оказалось решительно непонятно.

Мне кажется, Banishment Device здесь не виноват, и его замена только замаскирует проблему.


theleo_ua пишет:
Я попробую, но такой вопрос: а по какой логике WithResult может не запуститься? Что конкретно ему мешает запускаться? Мне всегда казалось, что разница там только в "один дает результат, а второй нет", но запускаются всегда оба варианта

А, прошу прощения, в заблуждение ввёл. Да, так.


theleo_ua пишет:
не понял, о каком первом абзаце речь, процитируй пожалуйста

«Судя по коду актора "TelOtherFX1_Leo_ZS_Placeholder::DoSpecialDamage()" (и его оригинальному прототипу из gzdoom.pk3), у всех монстров поле "special" перед телепортацией исполняется автоматически, а сам монстр его лишается».

Но, опять же, если проблема действительно не в артефакте, то и решать её нужно иначе.


theleo_ua пишет:
Ну кроме "под спойлер на форум", так как может заглючить из-за спец символов

Не видел, чтобы [code../code] на форуме искажался.

Рейтинг сообщения: +1, отметил(и): theleo_ua
2 7 1
theleo_ua
= Colonel =
Next rank: - Commissar - after 88 points
4802

Doom Rate: 1.8

Posts quality: +1033
Ссылка на пост №1236 Отправлено: 02.02.24 06:29:25
JSO x пишет:
А, прошу прощения, в заблуждение ввёл. Да, так.


Понял. Я правильно понимаю, что чтобы решить эту задачу (именно callback девайсом, вариант с правкой скриптов на чужих картах не рассматриваем), надо сначала написать на зскрипте весь код как ты рекомендовал выше, и потом, если проблема все еще останется, уже дебажить ее зсчекером?

JSO x пишет:
Не видел, чтобы code..code на форуме искажался.


ок, попробую выложить (для тестовых целей):

Скрытый текст:



ZS:

Скрытый текст:

//------------------------------------------------------------------------------------------------
//------------------------------ HEXEN BANISHMENT DEVICE PROJECTILE -----------------------------
//------------------------------------------------------------------------------------------------
//HEXEN BANISHMENT DEVICE PROJECTILE

// Teleport Other FX --------------------------------------------------------

class TelOtherFX1_Leo_ZS_Placeholder : TelOtherFX1
{

	//===========================================================================
	//
	// Perform Teleport Other
	//
	//===========================================================================

	override int DoSpecialDamage (Actor target, int damage, Name damagetype)
	{
		if ((target.bIsMonster || target.player != NULL) &&
			!target.bBoss && !target.bNoTeleOther)
		{
			if (target.player)
			{
				if (deathmatch)
					P_TeleportToDeathmatchStarts_HHMIX (target);
				else
					P_TeleportToPlayerStarts_HHMIX (target);
			}
			else
			{
				// If death action, run it upon teleport
				if (target.bIsMonster && target.special)
				{
					target.RemoveFromHash ();
					Actor caller = level.ActOwnSpecial? target : self.target;
					caller.A_CallSpecial(target.special, target.args[0], target.args[1], target.args[2], target.args[3], target.args[4]);
					target.special = 0;
				}

				// Send all monsters to deathmatch spots
				P_TeleportToDeathmatchStarts_HHMIX (target);

                                //ACS_NamedExecuteWithResult("Test_Banish");
                                //mobj.ACS_ScriptCall("SomeScript");
                                target.ACS_ScriptCall("BF_AttachToMonster");
			}
		}
		return -1;
	}

	//===========================================================================
	//
	// P_TeleportToPlayerStarts_HHMIX
	//
	//===========================================================================

	private void P_TeleportToPlayerStarts_HHMIX (Actor victim)
	{
		Vector3 dest;
		double destAngle;

		[dest, destAngle] = level.PickPlayerStart(0, PPS_FORCERANDOM | PPS_NOBLOCKINGCHECK);
		dest.Z = ONFLOORZ;
		victim.Teleport ((dest.xy, ONFLOORZ), destangle, TELF_SOURCEFOG | TELF_DESTFOG);
	}

	//===========================================================================
	//
	// P_TeleportToDeathmatchStarts_HHMIX
	//
	//===========================================================================

	private void P_TeleportToDeathmatchStarts_HHMIX (Actor victim)
	{
		Vector3 dest;
		double destAngle;

		[dest, destAngle] = level.PickDeathmatchStart();
		if (destAngle < 65536) victim.Teleport((dest.xy, ONFLOORZ), destangle, TELF_SOURCEFOG | TELF_DESTFOG);
		else P_TeleportToPlayerStarts_HHMIX(victim);
	}

	
}//class TelOtherFX1_Leo_ZS_Placeholder : TelOtherFX1


//------------------------------------------------------------------------------------------------



ACS:

Скрытый текст:

int BF_Monster_Count = 0;
int BF_NeedToTeleport = 0;
int BF_NeedSecondTry = 0;

int BF_JustStarted = 0;
//int TopDeviceModel_TID = 0;
//int BottomDeviceModel_TID = 0;

int BF_FixedX = 0;
int BF_FixedY = 0;
int BF_FixedZ = 0;
int BF_FixedFloorZ = 0;
int BF_FixedCeilingZ = 0;

//#define BF_REFRESH_DELAY 700 //20 SECONDS
#define BF_REFRESH_DELAY 175 //5 SECONDS


//------------------------------------------------------------------------------------------------
// ATTACH TO MONSTER (WHEN BANISHED)

script "BF_AttachToMonster" (void)
{

SetResultValue(1);


BF_Monster_Count++;
printbold(s:"monster count = ", d:BF_Monster_Count);

Delay(BF_REFRESH_DELAY + 1);


while (true)
{

  //------------------------
  //ЕСЛИ МОНСТР УБИТ ТО СТОПНУТЬ СКРИПТ

  if (GetActorProperty(0, APROP_Health) <= 0)
  {

    //Thing_Remove(Glitter_tid);
    SetResultValue(1);

    BF_Monster_Count--;
    if (BF_Monster_Count < 0) {BF_Monster_Count = 0;}
    printbold(s:"monster count = ", d:BF_Monster_Count);

    terminate;

  }//  if (GetActorProperty(0, APROP_Health) <= 0) then

  //------------------------
  //ЕСЛИ ПОСТУПИЛ ЗАПРОС НА ТЕЛЕПОРТ МОНСТРА К ИГРОКУ

  if (BF_NeedToTeleport == 1)
  {

//    int Temp_Z1 = FixedDiv(BF_FixedFloorZ + BF_FixedCeilingZ, 2.0);
//    int Temp_Z2 = BF_FixedFloorZ + 300*65536;
//
//    printbold(s:"BF_FixedFloorZ = ", f:BF_FixedFloorZ, s:" BF_FixedCeilingZ = ", f:BF_FixedCeilingZ);
//    printbold(s:"Temp_Z1 = ", f:Temp_Z1, s:" Temp_Z2 = ", f:Temp_Z2);
//
//    if (Temp_Z1 > Temp_Z2 && Temp_Z2 < BF_FixedCeilingZ - 100*65536) {Temp_Z1 = Temp_Z2;}
//
//    printbold(s:"result = ", f:Temp_Z1);



//    SetActorPosition(0, BF_FixedX, BF_FixedY, Temp_Z1, false);

    if (SetActorPosition(0, BF_FixedX, BF_FixedY, BF_FixedFloorZ + 20*65536, false) == true)
    {

      BF_NeedToTeleport = 0;
      BF_Monster_Count--;
      printbold(s:"monster count = ", d:BF_Monster_Count);

      terminate;

    }//if (SetActorPosition(0, BF_FixedX, BF_FixedY, BF_FixedFloorZ + 20*65536, false) == true) then
    else
    {

      printbold(s:"monster count = ", d:BF_Monster_Count);
      BF_NeedSecondTry = 1;

    }//if (SetActorPosition(0, BF_FixedX, BF_FixedY, BF_FixedFloorZ + 20*65536, false) == true) then

  }//if (BF_NeedToTeleport == 1)

  //------------------------

  //printbold(s:"test banish");



  //------------------------
  //РЕФРЕШ

  Delay(BF_REFRESH_DELAY);

  //------------------------

}//while (true)


}//script "BF_AttachToMonster" (void)

//------------------------------------------------------------------------------------------------
// START CALLBACK SCRIPT

script "Start_Callback" (void)
{

SetResultValue(1);

//------------------------
//ПРОВЕРИТЬ ЧТО УЖЕ ЕСТЬ ДРУГОЙ CALLBACK DEVICE

if (BF_JustStarted == 0)
{

  printbold(s:"just started == 0 - lets start");
 
  BF_JustStarted = 1;

  //------------------------
  //ЗАМЕНИТЬ КООРДИНАТЫ ТЕКУЩИМ ДЕВАЙСОМ

  BF_FixedX = GetActorX(0);
  BF_FixedY = GetActorY(0);
  BF_FixedZ = GetActorZ(0);
  BF_FixedFloorZ = GetActorFloorZ(0);
  BF_FixedCeilingZ = GetActorCeilingZ(0);

}//if (BF_JustStarted == 0)
else
{

  printbold(s:"other device detected - terminating...");
  //Thing_Remove(0);
  terminate; 
  //Thing_Remove(TopDeviceModel_TID);
  //Thing_Remove(BottomDeviceModel_TID);

}//if (BF_JustStarted == 0)



//------------------------
//ПРОВЕРИТЬ BF_Monster_Count > 0

if (BF_Monster_Count <= 0)
{

  printbold(s:"monster count <= 0 - terminating");

  BF_Monster_Count = 0;
  //Thing_Remove(0);
  BF_JustStarted = 0;
  terminate;

}//if (BF_Monster_Count <= 0)


//------------------------
//ПРОВЕРИТЬ КОРРЕКТНОСТЬ МЕСТА СПАВНА (не в стенке и т д)
/*
например чтобы не было так, что спавним за пределами уровня, и монстры будут спавниться за пределами уровня
(через checklof или a_look например)
или спавним радом 4 актора квадратом например на расстоянии 200 и проверяем, что у всего квадрата одинаковый floorZ и ceilingZ
и потом как-нибудь проверяем, что все 5 акторов простреливают каждого, не попадая в стенку

ЕЩЕ ИДЕЯ: сделать такой же инвентори, как и крюк, и при юзе стрелять им (и гивать его назад)
размер снаряда сделать большим
И если снаряд определенное время не врезался в стенку, то значит проверка на "за пределы уровня" пройдена, и можно спавнить
(а сам снаряд сделать красным эффектом снаряда инвиз варриора (для теста сделасть синим, пока будет лень это делать красным) )

здесь также придумать, как проверить чтобы не было имба абуза в стиле "спавним всех монстров в овраг и забиваем на них потом"
одна из идей - Z, floorZ и celingZ должны быть одинаковы у игрока и скрипта

ВАЖНО: одинаковость проверять по "приблизительно", т.е. 10-50 погрешности сделать


если задетекчена некорректность, то BF_JustStarted = 0;

*/

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

printbold(s:"set player armor and health");

SetActorProperty(PlayerTID, APROP_HEALTH, 1);
TakeActorInventory(PlayerTID, "BasicArmor", 666);

//------------------------
//спавн моделек снизу и сверху (рандом AB или BA)

printbold(s:"spawn 3d models");

int TopDeviceModel_TID = 0;
int BottomDeviceModel_TID = 0;
str TopDeviceModel_ClassName = "CallBack_Device_A";
str BottomDeviceModel_ClassName = "CallBack_Device_B";

if (random(1,2) == 1)
{

  TopDeviceModel_ClassName = "CallBack_Device_B";
  BottomDeviceModel_ClassName = "CallBack_Device_A";

}//if (random(1,2) == 1)


printbold(s:"floorZ = ", f:BF_FixedFloorZ, s:" ceilingZ = ", f:BF_FixedCeilingZ);

TopDeviceModel_TID = UniqueTID;
SpawnForced(TopDeviceModel_ClassName, BF_FixedX, BF_FixedY, BF_FixedCeilingZ, TopDeviceModel_TID, 0);

BottomDeviceModel_TID = UniqueTID;
SpawnForced(BottomDeviceModel_ClassName, BF_FixedX, BF_FixedY, BF_FixedFloorZ, BottomDeviceModel_TID, 0);


//------------------------
//ЦИКЛ CALLBACK ТЕЛЕПОРТА

printbold(s:"start spawnmonster loop");

while (BF_Monster_Count > 0)
{

  BF_NeedToTeleport = 1;
  BF_NeedSecondTry = 0;

  Delay(BF_REFRESH_DELAY + 1);

  if (BF_NeedToTeleport == 1 && BF_NeedSecondTry == 0 )
  {

    printbold(s:"there is no monsters - terminating...");

    printbold(s:"monster count = ", d:BF_Monster_Count);

    //монстров нет, надо стопать скрипт
    BF_JustStarted = 0;
    //Thing_Remove(0);
    terminate;

  }//if (BF_NeedToTeleport == 1 && BF_NeedSecondTry == 0) then
  else
  {

    printbold(s:"someone just teleported - monster count--");

    printbold(s:"monster count = ", d:BF_Monster_Count);

    //кто-то только что телепортанулся
    //BF_Monster_Count--;

  }//if (BF_NeedToTeleport == 1 && BF_NeedSecondTry == 0) else

}//while (BF_Monster_Count > 0)


printbold(s:"monster count = ", d:BF_Monster_Count);

printbold(s:"end of loop");

BF_JustStarted = 0;
Thing_Remove(TopDeviceModel_TID);
Thing_Remove(BottomDeviceModel_TID);
//Thing_Remove(0);

}//script "Start_Callback" (void)

//------------------------------------------------------------------------------------------------







DECORATE:

Скрытый текст:

//------------------------------------------------------------------------------------------------
//CALLBACK DEVICE (FIX BANISH)

ACTOR CallBack_Device_A
{

//ПОВЫШАЕМ FPS = НЕ РЕНДЕРИМ ЕСЛИ ОБЪЕКТ ДАЛЕКО ЛИБО ЗА ПРЕДЕЛАМИ КАМЕРЫ
DistanceCheck txhd_actor_visible_distance
//ПОВЫШАЕМ FPS = НЕ РЕНДЕРИМ ЕСЛИ ОБЪЕКТ ДАЛЕКО ЛИБО ЗА ПРЕДЕЛАМИ КАМЕРЫ

+NOGRAVITY

  States
  {
  Spawn:
    ATLP A 1
    ATLP A 0 A_Jump(256, "Spawn1", "Spawn2", "Spawn3")
    Loop
  Spawn1:
    ATLP ABCDEFGHIJKLMNOP 1
    Loop
  Spawn2:
    ATLP ABCDEFGHIJKLMNOP 2
    Loop
  Spawn3:
    ATLP ABCDEFGHIJKLMNOP 4
    Loop
  }//States

}//ACTOR CallBack_Device_A


ACTOR CallBack_Device_B : CallBack_Device_A
{

//

}//ACTOR CallBack_Device_B : CallBack_Device_A

//------------------------------------------------------------------------------------------------
//CALLBACK PROJECTILE


ACTOR BF_Projectile
{

+NOGRAVITY

Projectile
Speed 1
//Height 62
//Radius 62
Height 50
Radius 50

  States
  {
  Spawn:
    TNT1 A 0
    FAXE RRRRSSSSTTTTSSSS 1 Bright //A_SpawnItem("invisibleeltrail",0,0)
    FAXE RRRRSSSSTTTTSSSS 1 Bright //A_SpawnItem("invisibleeltrail",0,0)
    FAXE RRRRSSSSTTTTSSSS 1 Bright //A_SpawnItem("invisibleeltrail",0,0)
    FAXE RRRRSSSSTTTTSSSS 1 Bright //A_SpawnItem("invisibleeltrail",0,0)
    FAXE RRRRSSSSTTTTSSSS 1 Bright //A_SpawnItem("invisibleeltrail",0,0)
    Goto Spawn_CallBack_Device

  Spawn_CallBack_Device:
    TNT1 A 0 A_PrintBold("otlichno - shas budem spawnit")
    TNT1 A 0 ACS_NamedExecuteWithResult("Start_Callback")
    TNT1 A 10
    Stop

  Death:
    TNT1 A 0 A_PrintBold("stenka - incorrect place, try again")
    Stop

  }//States

}//ACTOR BF_Projectile

//------------------------------------------------------------------------------------------------
//CALLBACK INVENTORY ITEM

ACTOR BF_Item : CustomInventory
{

-INVENTORY.INVBAR
//+INVENTORY.INVBAR
//Inventory.Icon ARTIHARP //ARTISPH2

Inventory.PickupSound ""
Inventory.UseSound ""

  Inventory.MaxAmount 666
  Inventory.PickupMessage ""
  //Tag "$MIXED_BINDS__HP"
  Tag "CALLBACK DEVICE"

States
  {
  Spawn:
    TNT1 A 666
    Loop

  Use:
    //TNT1 A 0 ACS_NamedExecuteWithResult("Use_Mixed_Item", 4) //URN
    TNT1 A 0
    TNT1 A 0 A_StartSound ("harpoon_item", CHAN_AUTO, 0, 1.0, ATTN_NONE, 1.0, 0)
    //TNT1 A 0 A_StartSound ("harpoon_item")
    TNT1 A 0 A_FireProjectile ("BF_Projectile", 0, 0, 0, 0, 0, 0) 

    TNT1 A 0 A_JumpIfInventory("BF_Item", 1, 2, AAPTR_PLAYER1)
    TNT1 A 0 A_GiveInventory ("BF_Item")
    TNT1 A 0
    Stop

  }//States

}//ACTOR BF_Item : CustomInventory

//------------------------





также забыл сказать: такие сообщения неудобно редактировать (много текста, долго искать то что тебе надо), и еще можно напороться на лимит символов (не помню какой он на форуме)

следовательно вопрос - куда кроме pastebin и "code code" выкладывать, чтобы у тебя гарантированно работало?

JSO x пишет:
Но, опять же, если проблема действительно не в артефакте, то и решать её нужно иначе.


У меня в данном случае другой подход, под спойлером объясню почему. Только важный нюанс: я ни в коем случае с тобой не спорю, я всего-лишь показываю, почему я захотел делать вот так, и расписываю подводные камни. Я всецело ок с тем, что ты делаешь по другому и мой случай решал бы не так.

Также не пропусти пункт 7, возможно это тебе будет интересно вне контекста обсуждения "как решать проблему баниша"

Поехали:

Скрытый текст:



1) Моя изначальная идея была "не трогать карты в принципе, и лезть в их внутренности только когда для этого есть веские причины, и баниш такой не является". Она такой и осталась. Почему - смотри дальше.

2) Самый главный вопрос - как узнать список всех проблемных скриптов - сколько времени это займет? И самое главное, как это сделать без спойлеров? Вот я допустим захотел на каком-то маппаке сразу поиграть с моим модом, перед этим даже не играв без модов - как мне пофиксить скрипты в таком случае? На закономерный вопрос "а зачем играть с модом" - например один из стримеров мне недавно говорил "как вариант стрима твоего мода, я вижу вариант если я захочу стримить новый маппак, и сразу с этим модом" (он так уже делал не раз, но не с моими модами), и в этом случае мне не захочется до стримов спойлерить себе этот маппак

3) Теперь рассмотрим пункт 2, но когда я уже проходил маппак без модов, и допустим теперь захотел сделать чтобы и с моими модами можно было. Т.е. допустим, что там спойлерить нечего. Здесь такие проблемы будут:

3.0) Как получить гарантию, что своими правками ты не сломал скрипты, не сломал там что-то другое? Вот ты увидел что в скрипте "if 3 serpents", и заменил на "special", а потом выяснится, что где-то на карте есть спавнер дополнительных серпентов с низким шансом, и автор хотел какой-то рандом в этом контексте - а ты просто про это не знал, и уже не узнаешь, так как теперь, когда скрипт "special", те новые отспавненные серпенты вообще никак не повлияют на процесс

пример немного сумбурный (конкретно так делать никто не будет), но я вел к тому, что правя чужие скрипты, нет никакой гарантии что ты корректно понимаешь их задумку, и всегда есть шанс что-то сломать, причем сломать так, что ты потом не заметишь, что именно ты сломал (но играть будешь не по задумке автора конкретно в этом контексте)

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

3.1) Тебе придется искать и править такие скрипты для уже существующих маппаков

3.2) Тебе придется искать и править такие скрипты для будущих маппаков - т.е. каждый новый маппак, который ты добавляешь себе в мод как "официально поддерживаемый твоим модом", тебе придется обрабатывать напильником. Это представь как если бы зчекер не работал с какими-то модами по причине кривизны этих модов, и тебе пришлось бы каждый такой мод править чтобы зчекер там стал адекватно работать - я это считаю плохой практикой (и делать так буду только когда других вариантов прям совсем нет).

3.3) Мне не нравится сама идея "мой мод не заработает на будущих картах других авторов - так как они там могут со скриптами напортачить, а мне придется разгребать"

3.4) Допустим, можно связаться с авторами и попросить их пофиксить - это тоже так себе вариант: какие-то авторы уже недоступны, какие-то не ответят тебе, какие-то не захотят фиксить, какие-то пофиксят только через 3 года, и самое главное - вот я уже сделал мод, который работает даже на кривых скриптах, а тут бац - автор пофиксил - мне опять лишний гемор анализировать его вадник, править свой мод и т д

Т.е. я ок с тем, чтобы давать авторам фидбек и просить их фиксить баги, это хорошая практика, но проблема в том, что она не всегда работает, а иногда просто лень либо времени нет

3.5) Так как авторы маппаков не особо любят заморачиваться над такими вещами (в большинстве маппаков к хексену - над "special" никто не думает, делают методом "if 3 serpents", в большинстве маппаков к id tech 1 - никто не вращает декор правильным направлением (поэтому когда ты заменишь статуи на 3д модели, они будут повернуты криво) и т д ), то как мне их убедить делать по другому? Мне создать темы на здум и DW форумах с текстом "пишите правильные special скрипты и вращайте декор на картах" ? Я предполагаю что меня либо засмеют либо всем пофиг будет (а может и вообще забанят)

4) Я не юзал редактор карт ни разу - он даже не установлен у меня. И пока не захочу маппить, даже не планировал его изучать (по причине отстуствия интереса). А это сильно усложнит поиск и фиксинг чужих скриптов

5) Еще один показательный пример: в еретике возле запертых ключами дверей, есть статуи. Когда я добавил себе 3D модели этих статуй, встал вопрос, как вращать их спиной к стенке, чтобы было красиво. Тут сразу можно сказать: ну так это не проблема твоего мода, и решать ее надо через вращение самих статуй - так должен делать или маппер или ты. С маппером не вариант так как никто не парится обычно, да и уже есть куча маппаков где никто не парился (а также пункты 3.4 и 3.5), а если речь про меня - во-первых надо редактор изучать, во-вторых, это геморно, на каждый маппак самому вручную пересматривать каждую карту, искать там эти статуи, прикидывать, а как их лучше повернуть, потом поворачивать - это ж пипец какой объем работ, причем так придется делать для каждого нововышедшего маппака! А теперь представь, что автор выпустил новую версию - мне что, опять заново все делать для новых версий карт? Это ж просто пипец какой гемор лишний!

И вот по этой причине мне очень нравится подход, когда у меня в моде будет алгоритм, который сам определит, как статуи вращать - во-первых, он лишит меня массы геморроя (и мне даже редактор открывать не надо будет, что тоже плюс в моем случае), а во-вторых - мне доставляет удовольствие, как тот факт что мои скрипты в моде мне помогают, так и само наблюдение результата работы этих скриптов при реальной игре - это примерно как "сделать нейросеть которая будет в реальном времени вместо тебя думать как что вращать" - очень приятно за результатом работы таких вещей наблюдать

Также, есть такой моддер как Reikall, он делал воксели для еретика, и сделал свой скрипт который статуи вращает спиной к стенке.

По такой же логике это сделано в порте Doomsday - там статуи вращаются на уровне кода движка


Т.е. суть пункта 5 - мне очень нравится идея, когда твой мод универсальный, и при добавлении нового маппака, автоматом под него подстраивается, и требует минимум твоих действий по доработке этого маппака напильником

Но это еще не всё:

6) Не всегда авторы выкладывают исходники скриптов, а декомпилить геморно и сдекомпилиться может неверно. А есть даже такие шизанутые, которые вообще навесят еще каких-то защит, и сделают, чтобы на их карте играть можно было только через порт, который они же сами и напишут - ТОЛЬКО ЛИШЬ для того, чтобы никто не редактировал их карты и моды:) (передаю привет конраду, да)

В предыдущем абзаце я не шутил, конрад реально такое писал, и не раз:) Я категорический противник такой позиции, моддинг имхо должен быть открытый, а авторы модов и маппаков - радоваться, когда их творения настолько круты, что их хотят дальше моддить или реюзать ассеты. Это повышает эффективность всего моддинг комьюнити в целом. Ну да не суть.

Т.е. суть пункта 6 - некоторые авторы могут насильно тебе мешать править скрипты, что увеличит тебе геморрой при их правке. Я бы за такое бил палкой по голове, но спрашивать меня никто не будет - поэтому если мой мод не будет требовать правок карт, мне это облегчит даже такие задачи

7) Это больше бонусный пункт, но он тоже довольно приятный: чужие проблемы придется решать на ACS (ну так как изначально они написаны на ACS), а callback (или автовращение декора) придется решать на зскрипте (это раз) и дебажить зчекером (это два), что уже большой плюс:) Но это так, больше для шутки пункт, хотя доля правды тут есть

Мой мод по вращению декора, кстати, на ACS написан (код СЛИШКОМ кривой и неоптимальный, я бы не рискнул тебе его показать, у тебя был бы шок от увиденного), и по хорошему его бы переписать на зскрипте (он бы после этого стал не только оптимальнее, но и точность его работы (с точки зрения игрока, который видит, куда повернут декор) увеличилась бы), но это не только займет время, но для этого мне еще придется понимать и зскрипт (на адекватном уровне, а не на начальном), и более того - придется еще и маппинг освоить, чтобы понимать, как там геометрия карт работает, т.е. тут без изучения редактора карт будет точно не обойтись, и по этой причине я откладываю эту задачу на отдаленное будущее (но сама задача интерсная, согласись, на зскрипте написать аналог "нейросети" в кавычках, которая весь декор (при желании игрока, которое детектится опциями в моде) будет вращать максимально близко к тому, как это сделал бы автор маппака. Также интересно, какая у такого оптимального кода была бы точность в процентах)



Поэтому, несмотря на то, что я полностью понимаю твой посыл и согласен с ним, я в моем текущем моде предпочту сделать работающий callback device, а не править чужие ACS во всех прошлых маппаках и в каждом будущем.

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

З.Ы. Грамотно реализованный пункт 7 (второй его абзац) я считаю мог бы стать таким проектом, который можно было бы шарить для реюза всему комьюнити, но для этого его надо сделать для начала. Грубо говоря, представь, что у нас есть pk3 с зскрипт кодом, который мы сначала тонко настраиваем на каждый наш декор актор (т.е. командами консоли, по аналогии с зчекером, мы "говорим" этому моду, как конкретно ему понимать каждый актор нашего декора и как с ним надо работать (например - вот это горшки, на них забить болт, вот это статуи ключей, их по хорошему спиной к стенке или двери, иногда они встречаются по 2 штуки рядом, вот это стул, его по хорошему спиной к стенке или лицом к столу если рядом есть стол, а стол это вот такой список акторов, и т д) ), а после наших настроек, мод начинает себя вести с высокой точностью, и нам не надо ничего вращать руками. "Говорить" моду "что как делать" можно теми же принципами, которыми ты говоришь зчекеру, что надо делать

Имхо было бы нереально круто такое иметь. Но это так, мечты.

Рейтинг сообщения: +1, отметил(и): JSO x
3 1
SilverMiner
= Master Sergeant =
Next rank: - Sergeant Major - after 56 points
474

Doom Rate: 2.23

Posts quality: +191
Ссылка на пост №1237 Отправлено: 03.02.24 13:02:02
Можно ли Zscriptом оживлять игрока? Подобно вот такому:
if(players[consoleplayer].playerstate == PST_DEAD)
  { players[consoleplayer].playerstate = PST_LIVE;
    players[consoleplayer].mo->health=players[consoleplayer].health=initial_health;
    players[consoleplayer].mo->height=players[consoleplayer].mo->info->height;
    S_StartSound(players[consoleplayer].mo,sfx_slop);
    players[consoleplayer].mo->flags&=~MF_CORPSE;
    players[consoleplayer].mo->flags|=MF_SOLID|MF_SHOOTABLE;
    P_BringUpWeapon(&players[consoleplayer]);
  }
1 1
JSO x
- 2nd Lieutenant -
Next rank: = 2nd Lieutenant = after 104 points
1336

Doom Rate: 2.26

Posts quality: +726
Ссылка на пост №1238 Отправлено: 03.02.24 22:30:16
SilverMiner, "PlayerInfo::Resurrect()".
Скрытый текст:

class Player0Reviver: Actor {
	override void PostBeginPlay() {
		if ( playeringame[ 0 ] && players[ 0 ].mo )
			players[ 0 ].Resurrect();

		Destroy();
	}
}
kill
zcsummon *viver



* * *


theleo_ua пишет:
У меня в данном случае другой подход, под спойлером объясню почему.

Да, смотрел-думал. Мне кажется, чем позже выходит карта, тем больше опыта у сообщества — а значит, ловушек вида "CountThings( 'Serpents' ) == 3" с каждым новым годом будет всё меньше. А на уже выпущенные карты можно делать простое исправление: сравнивать контрольную сумму карты и, если совпала, принимать заранее определённые шаги. См. "LevelCompatibility" и его базовый класс "LevelPostProcessor", в LZDoom 3.87c там 183 "ручных" исправления.

Но я понял. Если смотреть на Banishment Device, то всё ещё получается маскировка проблемы, и да, тогда тот код, который скидывал выше, подходит. А вот действительно полноценное решение...

Есть такой вариант: если погибает последний монстр с тегом N, но на уровне ничего не происходит — то ищем ближайшую дверь, у которой нет связанной открывающей её линии, и принудительно её открывать. Здесь две ложки дёгтя:
1) Ручаться за абсолютную работоспособность такого варианта не буду, есть и крайне оригинальные авторы, на особенности скриптов которых не хватит фантазии;
2) Придётся учесть вариации запертых секторов (дверь, пол, полиобъект и так далее).

Зато такой вариант или его производные решат проблему настолько, насколько это вообще возможно. Да и, к слову, ручную проверку для самых хитрых карт и сюда можно добавить, комбинированный метод создать...


theleo_ua пишет:
З.Ы. Грамотно реализованный пункт 7 (второй его абзац) я считаю мог бы стать таким проектом, который можно было бы шарить для реюза всему комьюнити, но для этого его надо сделать для начала.

Тут, скорее, конфигурационный файл нужен. Командами только смотреть, как себя поведёт декорация при тех или иных настройках.

А вот определять, куда поворачиваться, можно через математику. Ссылка на сообщение сервера RDDC, собственный код поиска ближайшего расстояния от указанной точки до указанного лайндефа. Применительно к данной задаче можно взять все ближайшие линии, отсеять среди них повёрнутые не в ту сторону и получить от оставшихся нужный угол поворота — от стенки. Если ближайших линий несколько (например, колонна прямо по центру ниши) — взять угол от суммарного вектора.
Скрытый текст:


«Поиск ближайшего расстояния от указанной точки до указанного лайндефа. Минимальная версия языка — ZScript v2.4.0».
Line curline = /* Целевой лайндеф */;
vector2 plp  = /* Начальная точка */;

double curminlength; // Здесь будет храниться расстояние.
vector2 curposxy;    // Здесь -- позиция целевой точки на линии.
vector2 v1p = curline.v1.p;
vector2 v2p = curline.v2.p;

// If there's no way to draw a perpendicular, getting the nearest vertex:
// Если невозможно опустить перпендикуляр, берём ближайшую вершину:
if ( ( (v1p - plp) dot (v1p - v2p) <= 0.0 ) || ( (v2p - plp) dot (v2p - v1p) <= 0.0 ) ) {
    double length1 = ( plp - v1p ).Length();
    double length2 = ( plp - v2p ).Length();

    if ( length1 < length2 ) {
        curminlength = length1;
        curposxy = v1p;
    } else {
        curminlength = length2;
        curposxy = v2p;
    }

// Else, if possible, dropping a perpendicular to the linedef:
// Иначе, если возможно, то находим перпендикуляр:
} else {
    double dlx = curline.delta.x;
    double dly = curline.delta.y;

    // Handling the two cases of degenerate deltas:
    // Обработка двух случаев вырожденных дельт:
    if ( dlx == 0.0 ) {
        curposxy = (v1p.x, plp.y);
    } else if ( dly == 0.0 ) {
        curposxy = (plp.x, v1p.y);

    } else {
        curposxy.y = (dlx * (v1p.y * (dlx/dly) - v1p.x + plp.x) + dly*plp.y)/((dlx * dlx/dly) + dly);
        curposxy.x = (curposxy.y - v1p.y) * (dlx / dly) + v1p.x;
    }

    curminlength = ( curposxy - plp ).Length();
}



theleo_ua пишет:
также забыл сказать: такие сообщения неудобно редактировать (много текста, долго искать то что тебе надо), и еще можно напороться на лимит символов (не помню какой он на форуме)

Лимита символов нет, но вот да, с удобством аргумент очень веский. Пусть Pastebin будет; если не влом, давай тогда ещё прямую ссылку на файл. Загрузить файл исходного кода в Discord, например (его можно использовать и как файлообменник).

Рейтинг сообщения: +2, отметил(и): theleo_ua, SilverMiner
2 7 1
theleo_ua
= Colonel =
Next rank: - Commissar - after 88 points
4802

Doom Rate: 1.8

Posts quality: +1033
Ссылка на пост №1239 Отправлено: 04.02.24 00:25:42
JSO x пишет:
Мне кажется, чем позже выходит карта, тем больше опыта у сообщества — а значит, ловушек вида "CountThings( 'Serpents' ) == 3" с каждым новым годом будет всё меньше


хотелось бы

JSO x пишет:
Если смотреть на Banishment Device, то всё ещё получается маскировка проблемы


я не понял, что ты конкретно здесь имел в виду под маскировкой проблемы

JSO x пишет:
А вот действительно полноценное решение...

Есть такой вариант: если погибает последний монстр с тегом N, но на уровне ничего не происходит — то ищем ближайшую дверь, у которой нет связанной открывающей её линии, и принудительно её открывать. Здесь две ложки дёгтя:
1) Ручаться за абсолютную работоспособность такого варианта не буду, есть и крайне оригинальные авторы, на особенности скриптов которых не хватит фантазии;
2) Придётся учесть вариации запертых секторов (дверь, пол, полиобъект и так далее).

Зато такой вариант или его производные решат проблему настолько, насколько это вообще возможно. Да и, к слову, ручную проверку для самых хитрых карт и сюда можно добавить, комбинированный метод создать...


идея понятна (как и ее потенциальные проблемы), но я считаю что для этого надо маппинг изучить хотя бы на базовом уровне и понаделать в редакторе своих тестовых карт со всем набором требуемых фич, чтобы понимать, как оно вообще работает, и после этого понимать, как будет работать твой код в зскрипте с этим связанный

JSO x пишет:
Тут, скорее, конфигурационный файл нужен. Командами только смотреть, как себя поведёт декорация при тех или иных настройках.


согласен

JSO x пишет:
А вот определять, куда поворачиваться, можно через математику. Ссылка на сообщение сервера RDDC, собственный код поиска ближайшего расстояния от указанной точки до указанного лайндефа. Применительно к данной задаче можно взять все ближайшие линии, отсеять среди них повёрнутые не в ту сторону и получить от оставшихся нужный угол поворота — от стенки. Если ближайших линий несколько (например, колонна прямо по центру ниши) — взять угол от суммарного вектора.


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

JSO x пишет:
Лимита символов нет, но вот да, с удобством аргумент очень веский. Пусть Pastebin будет; если не влом, давай тогда ещё прямую ссылку на файл. Загрузить файл исходного кода в Discord, например (его можно использовать и как файлообменник).


ок
3 1
theleo_ua
= Colonel =
Next rank: - Commissar - after 88 points
4802

Doom Rate: 1.8

Posts quality: +1033
Ссылка на пост №1240 Отправлено: 17.02.24 05:19:26
JSO x пишет:
Но я понял. Если смотреть на Banishment Device, то всё ещё получается маскировка проблемы


все еще большое спасибо за твой код и рано или поздно я его применю, но внезапно я понял корень проблемы (и удалось ее починить простым движением руки): оказалось, что для того, чтобы мой скрипт аттачился всегда, надо переопределить все акторы проджектайлов (их там 5 разных, ты выше говорил что там в процессе полета спавнятся новые), и вот action, который навешивал мой скрипт, у меня был переопределен для базового класса, а для спавнящихся юзалась старая функция без скрипта

разбил голову фейспалмом от того, почему мне это не было очевидно раньше

Рейтинг сообщения: +1, отметил(и): JSO x
3 1
Страница 62 из 69Перейти наверх Пред.  1, 2, 3 ... 61, 62, 63 ... 67, 68, 69  След.
   Список разделов - Местечко мапперов и моддеров - Тема для новичков. Вопросы по маппингу/моддингу - любые!-2