Перейти к контенту

[SoC] Ковыряемся в файлах


Halford

Рекомендуемые сообщения

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

Где-нибудь в xr_conditions пишем такой код:

local random_dialog = nil
function get_random_dialog(actor, npc, p)
	local max_count = p and p[1] or 1

	if random_dialog == nil or random_dialog.counter >= max_count then
		random_dialog = {dialog_set = false, counter = 1}
	else
		random_dialog.counter = random_dialog.counter + 1
	end

	math.randomseed(time_global())
	if not random_dialog.dialog_set then
		random_dialog.dialog_set = random_dialog.counter == max_count or math.random(random_dialog.counter, max_count) == max_count
		return random_dialog.dialog_set
	else
		return false
	end
end 

Затем в логике пишем так (пример для трёх равнозначных диалогов):

meet_dialog = {=get_random_dialog(3)} dialog1, {=get_random_dialog(3)} dialog2, {=get_random_dialog(3)} dialog3 

Важно:

1. аргумент, передаваемый в функцию, должен быть равен общему числу диалогов;

2. функцию обязательно надо использовать в том числе для последнего диалога в цепочке, чтобы не сбился внутренний счётчик;

3. дополнительные условия (например инфопорции) при таком подходе использовать нельзя;

4. данная реализация может быть применима только к одному конкретному выбору случайного диалога. Если необходимо применить аналогичный подход в нескольких местах (с разным количеством диалогов для выбора), из переменной random_dialog надо делать массив, а в функцию передавать 2 аргумента - номер комплекта диалогов и кол-во диалогов в этом комплекте. Соответсвенно и код функции претерпит небольшие изменения.

 

При таких последовательных вызовах функция случайным образом назначит активным один из диалогов.

При повторной попытке заговорить счётчик диалогов сбросится и случайный выбор будет сделан заново.

Изменено пользователем Kirgudu
  • Нравится 2

Поделиться этим сообщением


Ссылка на сообщение

@BoBaH_671, вот понятия не имею. Но не исключено. Почему бы не проверить, если есть возможность? ;)

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

Изменено пользователем Kirgudu

Поделиться этим сообщением


Ссылка на сообщение

Только у меня диалог после открытия практически сразу исчезает.

Это потому, что настройки диалога у тебя неправильные. Дело в том, что необходимость выбора того или иного диалога рассчитывается последовательно, а вероятности при расчёте не складываются. Смотри:

meet_dialog = {~30} dialog1, {~60} dialog2, {~10} dialog3
Первый диалог будет выбран с вероятностью 30% (число сравнивается со случайным числом в диапазоне от 1 до 100, если больше - сработало). 70% - вероятность, что не будет выбран.

Второй диалог будет выбран с вероятностью 60%, но относительно 70% вероятности не выбора первого диалога. Общая вероятность выбора второго диалога 0.7*0.6*100% = 42%. Отсюда 30%+42% = 72% - вероятность выбора первого или второго диалога, 28% - вероятность не выбора.

Третий диалог будет выбран с вероятностью 10%, но уже от этих оставшихся 28%. Общая вероятность выбора третьего диалога составит 0.1*0.28*100% = 2.8%. Отсюда 72%+2.8% = 74.8% - общая вероятность выбора одного из трёх диалогов.

Получается, с вероятностью 100%-74.8% = 25.2% никакой диалог не будет выбран. И даже если у тебя получилось при начале разговора попасть в «правильные» 74.8% - на апдейте, тут ты прав, происходит выбор диалога заново, с некоей вероятностью он оказывается пуст, и в таком случае в скрипте логики происходит вызов функции restore_default_start_dialog(). Возможно, именно она и закрывает диалоговое окно - движкоправы могут сказать точнее.

Чтобы условие гарантированно приводило к какому-либо диалогу, необходимо, чтобы последний диалог в цепочке от вероятности не зависел:

meet_dialog = {~30} dialog1, {~60} dialog2, dialog3
Но и тогда диалоговое окно теоретически может сбрасываться, если во время апдейта новый выбранный диалог будет отличаться от старого - для смены диалога в таком случае вызывается функция set_start_dialog(dialog). Вызывает ли эта функция аналогичное закрытие диалогового окна, мне неизвестно. Надо проверять.

 

Update: Прошу считать данный пост недействительным - причина ниже.

Изменено пользователем Kirgudu
  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение

@Х_и_м_и_к,

active = sr_idle

[sr_idle]
on_actor_inside = {+top_bor} nil %=xr_effects.hana_ano%
вот этот вот "nil" завершает работу данной логики. Окончательно и бесповоротно.

Соответственно, раз зайдя в рестриктор, ты сам же запрещаешь повторное его срабатывание.

Изменено пользователем Kirgudu
  • Спасибо 1

Поделиться этим сообщением


Ссылка на сообщение
2 часа назад, AndrewMor сказал:

Отец Диодор на Складах. Перерыл все, но никак не могу найти файл, где его логика описывается

Нет у него персональной логики.

  • Сомнительно 1

Поделиться этим сообщением


Ссылка на сообщение

@Akello автор вопроса уже за меня ответил. Я тоже не вижу там никакой логики.
Но если ты знаешь то, что не знаем мы - ткни носом, будь любезен. Мало ли кому пригодится.

 

@AndrewMor, возможно, всё дело во флагах (0xffffffbf). Не исключено, что это как раз установка «не двигаться»; навскидку значения не помню.

Поделиться этим сообщением


Ссылка на сообщение
В 12.11.2017 в 20:59, UriZzz сказал:

если в координатах рестриктора понятно что за скобками находятся вертексы то вот у кошки целых 3 числа - 1, 44, 2 вот эти числа мне и не понятны

1 и 44 - как уже было выше отвечено, вертексы, а 2 - это кол-во спавнящихся в одном месте кошек.

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

  • Спасибо 1

Поделиться этим сообщением


Ссылка на сообщение

@AndrewMor, лично делал для этого мода, взяв за основу более простой вариант от @Shoker.

Это, конечно, ЧН. Но дам наводку: в ТЧ, насколько я знаю, в биндере актора тоже есть коллбэк trade_sell_buy_item (в аргументах - текущий объект торговли, булевый признак покупка/продажа, стоимость), на который по дефолту зацеплено только изменение статистики движения денег. Не слишком сложно прикрутить к этому событию свой обработчик торговли, в котором проверять состояние предмета (а также, по желанию, другие условия) и при необходимости делать возврат во время ближайшего апдейта с выдачей соответствующего сообщения на худ или как-то иначе. Важный нюанс: коллбэк trade_sell_buy_item срабатывает непосредственно перед реальной передачей предметов, то есть у каждого предмета в этот момент ещё старый владелец (obj:parent()). При этом в тот же момент коллбэка деньги за покупку/продажу уже засчитаны актору или торговцу. Это надо учитывать при написании возврата.

  • Спасибо 1
  • Полезно 1

Поделиться этим сообщением


Ссылка на сообщение
9 часов назад, Graff46 сказал:

Некоторые объекты имеют флаг used_ai_location, выставляется он в СДК. А где хранятся он? В нетпакетах не нашел...

Если адресоваться к пакету m_netpk, следует смотреть в свойстве net_cse_alife_object.st_props.object_flags. Нужный тебе флаг имеет значение 128 и, кстати, при подключении модуля выводится глобально в составе _G.object_flags.

 

@dsh, синхронно. :)

Поделиться этим сообщением


Ссылка на сообщение

Если по-простому, то в функции drop_manager:create_release_item() добавляем в нужном месте что-то вроде

if ranks.get_obj_rank_name(self.npc) == 'novice' then -- 'novice'|'experienced'|'veteran'|'master'
  -- do something
end

А если хочется реализовать полноценное решение через конфиг, то необходимо добавить, например, файл "misc\death_items_by_ranks.ltx", заполнить его аналогично конфигу "death_items_by_communities.ltx" значениями вероятностей для каждого ранга

[novice] ;Указывается вероятность заспаунить или нет
af_medusa				= 0.015
; и т. д.

заинклудить новый конфиг в "death_generic.ltx", затем поработать с модулем drop_manafer.script: организовать чтение в новую таблицу множителей вероятности из нового конфига в init_drop_settings(), дополнить drop_manager:create_release_item() учётом значений из новой таблицы.

Работа муторная, но при желании сделать можно за вменяемое время.

  • Спасибо 1
  • Полезно 1

Поделиться этим сообщением


Ссылка на сообщение

@div, изменив нужное свойство в абстрактной части нет-пакета объекта.
Например, можно воспользоваться модулем m_netpk от Артоса (если мы говорим о ванильном движке; в модифицированных это, возможно, сделать куда проще).

Модуль можно взять здесь:

Авторский пример изменения координат см. в описании внутри архива с модулем.

  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение

@div, нет, я писал про пункты 1), 2) и 3) чуть пониже процитированной строки.
Но это действительно может быть совершенно не важно. Речь-то, как справедливо тут заметили, о версии 1.0004, а я на это не обратил внимания. Модуль Артоса предназначен для 1.0006.

  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение
1 час назад, div сказал:

В readme_m_netpk версия 1.0004 вроде подходит

Может и так, не проверял. Правда, внутри самого модуля она в шапке не упомянута.

11 часов назад, Zander_driver сказал:

Интересно, а как модуль это на 1.0004 сделает? Возможно я уже плохо помню, но без подключения к апдейту, там это нетривиальная задача, разве нет?

@Zander_driver, кстати, там level.add_call под капотом, см. do_switchings и execute_switchings. Так что очень может быть, что заработает.

1 час назад, div сказал:

переключить примерно так нужно:

Не нужно. При изменении абстрактной части нет-пакета модуль проделывает необходимые манипуляции автоматически, как и написано в readme. Если интересно, см. упомянутые выше функции модуля do_switchings и execute_switchings, там всё уже есть.

1 час назад, div сказал:

значит нужно еще файл se_item.script проверить / изменить.

Для NPC - скорее se_stalker.script

1 час назад, div сказал:

выше поверхности карты и не стоял на каком-то объекте

Не уверен, что подействует на живой объект, но можно попробовать при спавне НПС снять флаг use_ai_locations  =  128 (привязка к сетке). Делается это в том же модуле m_netpk, примеры есть на форуме, например этот из свежих: 

 

В общем, дальше надо экспериментировать.

  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение
1 час назад, Zander_driver сказал:

Но, что при этом отвалится в логике НПС? Любопытный вопрос, на который у меня нет ответа. Но памятуя о том, что в коде обслуживающем действия НПС, обращения к АИ-сетке встречаются на каждом шагу, подозреваю что будут проблемы.

Тоже не знаю. Убирал флаги перехода в оффлайн у БТР, сбрасывал какие-то флаги у физ. объектов - проблем не было. НПС спавнить в воздухе в голову не приходило.

  • Согласен 1

Поделиться этим сообщением


Ссылка на сообщение

@div готовый тестовый пример с вентилятором:
https://disk.yandex.ru/d/T2v4KZ0WfBOp4g
Внутри сейвы у Сидоровича и в подвале деревни после переноса (сделаны на Steam версии ТЧ, поэтому скорее всего не загрузятся), скриншоты для визуального подтверждения.

Для лёгкости понимания вставок упаковал 2 папки: оригинальную из Steam-версии и уже с изменениями. WinMerge или аналог покажет разницу между изменёнными файлами.

Не мудрствуя лукаво, повесил запуск телепорта вентилятора на апдейт актора, через 10 секунд после первого апдейта (чтобы успеть сбросить начальный ролик и увидеть телепорт глазами).
Дальше самостоятельно, код писать больше не буду. Имхо, технических сведений вполне достаточно, может просто не хватило внимательности при реализации.

  • Спасибо 1
  • Нравится 3

Поделиться этим сообщением


Ссылка на сообщение

@div, ну тут одно из двух: либо дьявол в неучтённых мелочах, либо, как мы раньше писали, для NPC это не сработает.
Изучать и экспериментировать.

Поделиться этим сообщением


Ссылка на сообщение
10 минут назад, div сказал:

я наверно не тот флаг снимаю :facepalm:

data.object_flags = bit_and(data.object_flags, bit_not(128)) -- сброс UsedAI_Locations

Полный список флагов можно посмотреть в том же m_netpk в конце файла, где "_G.object_flags = ..." и далее.

  

10 минут назад, div сказал:

так же должно быть?

Или так, наверное. Только что-то одно.

Изменено пользователем Kirgudu

Поделиться этим сообщением


Ссылка на сообщение
1 час назад, Zander_driver сказал:

прокомментируй

Ну конечно. Иначе как раз переключение оффлайн-онлайн работать не будет.
А class_registrator в большинстве случаев нужен только затем, чтобы посмотреть, какой биндер и где искать.

1 час назад, div сказал:
data.object_flags = bit_xor(data.object_flags, 128)
data.object_flags = bit_or(data.object_flags, 128)

Потому что вызов данных команд в паре приводит к исходному положению дел. Ведь даже в комментарии поста

сказано, что первая - сброс флага, тогда как вторая - поднятие оного. В итоге флаг привязки к сетке после парного выполнения остаётся установленным.


Аптечки... честно говоря, не помню, есть ли у них биндер в принципе.

Изменено пользователем Kirgudu

Поделиться этим сообщением


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...