Пользователей: 2
Гостей: 969
Всего: 971

» Подробно
» Сегодня

Привет, гость!









Автор Сообщение
Strchi
    
Посты: 2581
Откуда: Уфа-Челябинск-Фритаун
Возраст:
28-01-2013 23:00 GMT3 час. #1652496   
dimak

перл скрипты? интересно я пробовал не вышло( вот пользоваться асдс не умею видимо не все еще в асдс знаю)
нормик все временно только прекратил работу из за занятости


Fagot_
    
Посты: 283
Откуда: СССР, Владивосток.
Возраст: 131
29-01-2013 05:00 GMT3 час. #1652502   
dimak , я умею пользоваться АСДС, проблема в game.graph. На АМК есть программа , которая работает с этим файлом, но у меня при открытии game.graph-а от МГ она выдаёт ошибку, а от ТЧ открывает нормально. Т.е. и с помощью программы от АМК (ggEditor_01) не получается присоединить локу.


Я давно хотел вас спросить, как художник художника - вы рисовать умеете?..
Fagot_
    
Посты: 283
Откуда: СССР, Владивосток.
Возраст: 131
29-01-2013 09:31 GMT3 час. #1652511   
Strchi, так: "ты не копируй оллспавн и все добавь в оллспавн вей и алайф города и все" не получится, я пробовал - вылет. (если я правильно понял, что ты имеешь ввиду. Без знаков препинания не совсем понятно.)


Я давно хотел вас спросить, как художник художника - вы рисовать умеете?..
voven
    
Посты: 260
Откуда: Москва
Возраст: 27
29-01-2013 18:10 GMT3 час. #1652584   
Скачал билд 2205, и при загрузке xr_3da.exe вылетает с ошибкой

*** Fatal Error***
Can't open section 'sound'

Ошибка возможно связана с файлами в папке bin. Кто может, прошу помощи.


frankenshtayn
    
Посты: 203
Откуда:
Возраст: 52
29-01-2013 19:30 GMT3 час. #1652600   
приветствую, подскажи**50012a1699cdd64639ea**

отредактировал(а) frankenshtayn: 29-01-2013 22:06 GMT3 час.

И ЭТО ПРОЙДЕТ...
Struck
    
Посты: 1946
Откуда:
Возраст:
29-01-2013 23:15 GMT3 час. #1652634   
frankenshtayn сохрани в пстор например.


Снова в строю.

l
Strchi
    
Посты: 2581
Откуда: Уфа-Челябинск-Фритаун
Возраст:
29-01-2013 23:36 GMT3 час. #1652638   
voven не обязательно в бин... возможно если секция саунд в конфигах,поройся там...


dimak
    
Посты: 1493
Откуда: Архангельск
Возраст: 52
30-01-2013 20:03 GMT3 час. #1652692   

По моему, без СДК на ТЧ локацию не подключить.


Свободно. Я же подключил Даркскейп.

добавлено спустя 5 минут

Fagot_
Утилита для слияния глобальных графов
ggrc.pl v.0.7


Кратко о сути. Чтобы подключить локацию в какую-нибудь версию сталкера необходимо наличие xrAI для этой версии
и исходники ВСЕХ локаций, которые подключаются в сингл. При отсутствии исходников придется возиться с декомпиляцией
уровней с последующей их компиляцией. При отсутствии xrAI - пролетаем полностью. Разберемся, что делает xrAI:
1) компилит АИ-сетку из исходников, формирует локальный граф уровня.
2) соединяет локальные графы в глобальный граф и формирует кросс-таблицы.
3) соединяет спавны локаций в один.

Казалось бы, если нет xrAI - можно опустить руки. С другой стороны, аи-сетки и кросс-таблицы в скомпиленных
локациях уже есть. Есть и глобальный граф, куда включены локации. Таким образом, в теории подключение
сингл-локаций без исходников к какой-либо версии сталкера подразумевает под собой следующие действия:
1) Совмещение глобальных графов.
2) Правка ресурсных файлов уровней, если их версия отлична от версии игры, к которой происходит подключение.
Список таких файлов:
-level.gct.
-level.ai.
-level, level.cform, level.geom/geomx (если работать с билдами ранее 2201)
-level.graph (ряд билдов вроде как требует его наличия)
3) Всякие мелкие дела, вроде копирования недостающих ресурсов, совмещения материалов, шейдеров и партиклов.

Нетрудно догадаться, что подключение локаций вручную требует долгого времени и прекрасное знание форматов
глобального графа и ресурсных файлов. Данная утилитка призвана облегчить этот процесс.
Что она делает:
-перемещает графы локаций из одного глобального графа в другой. Также может удалить из дополняемого
графа любые локации, если нужно.
-правит level.ai, level.gct, level
-генерирует level.graph, если его в ресурсных файлах нет.
Также присутствует дополнительный функционал для удобства - создание аи-переходов и распаковка графа.


Использование:
----------------------------------------------------
--------------СОВМЕЩЕНИЕ ГРАФОВ---------------------
----------------------------------------------------


1) Кладете программу (ggrc.pl и папку stkutils) в корень геймдаты, в папке levels которой есть все нужные локации.
2) кидаете глобальный граф, из которого будете переносить локации, туда же - в корень геймдаты. Напомню,
глобальный граф в ТЧ и ранее - это файлик game.graph, в ЧН и позднее он называется section4.bin и находится
в all.spawn. Чтобы его достать, распакуйте all.spawn с помощью acdc.
3) Делаете батник для сборки (ниже есть пример), запускаете. Если батник составлен правильно, заработает скрипт,
который будет вас информировать о ходе работы всякими буковками. Работать может долго, вплоть до нескольких
минут, так что ждите. Совет - не работайте со скриптом на флешке, ждать придется оооочень долго.
4) На выходе получите:
-в корне геймдаты результирующий граф - game.graph.new
-в папках уровней файлы level.gct, level.ai, level, level.graph. Кстати, если переносите локи в ЧН или ЗП -
level.gct НЕ появится. Это нормально.
5) переименовываете game.graph.new в game.graph (ну или в section4.bin, если родительский граф у вас от ЗП),

Чтобы добавить подключенные локации в спавн, в all.ltx распакованного спавна в секции [alife_objects]
добавляете alife_локация.ltx от ваших локаций. Еще поменяйте level_count в секции [header] на значение
согласно получившегося графа.

Главное, не трогайте больше ничего в [header]!

Ну вот и все. Можно запускать игру, ловить вылеты по недостающим текстурам и т.д. и т.п.

Синтаксис батника:
ggrc.pl [-g1 <имя_графа,номер_билда>] [-l1 <список уровней>] [-g2 <имя_графа,номер_билда>] [-l2 <список уровней>]
[-rscan]

Значения параметров:
-g1 <имя_графа,ключ_билда> - родительский граф, т.е. от того билда, к которому вы планируете присоединить локации.
указывается в формате: game.graph,1935. Список ключей смотрите ниже.
-l1 <список уровней> - список уровней, которые хотите оставить в родительском графе, через запятую (без пробелов!)
-g2 <имя_графа,ключ_билда> - дочерний граф, т.е. от того билда, откуда берете локации.
указывается в формате: game.graph,1935. Список ключей смотрите ниже.
-l2 <список уровней> - список уровней, которые хотите взять из дочернего графа, через запятую (без пробелов!)
-rscan - при указании этого ключа скрипт прочитает текстуры, шейдеры и материалы, необходимые
для подключаемых локаций, и сравнит их с присутствующими в геймдате. При отсутствии запишет имя недостающего
в файл res.log.

!!!Внимание! Уровни указывать в том же порядке, в каком они идут в гейм.графе!

!!!Для совмещения графов БОЛЬШЕ НИКАКИХ КЛЮЧЕЙ НЕ УКАЗЫВАТЬ!

Пример: ggrc.pl -g1 game.graph,soc -l1 l01_escape,l02_garbage -g2 section4.bin,cop -l2 zaton,pripyat

Не будет лишним заметить, что имена уровней надо указывать ТОЧНО ТАКЖЕ, как они записаны в глобальном графе.
Если не уверены в именах - распакуйте граф и посмотрите.

------------------------------------------------------------
--------------------РАСПАКОВКА ГРАФА------------------------
------------------------------------------------------------

Использовать просто. Кладете граф в папку с программой, запускаете батник для распаковки.

Команда:
ggrc.pl [-g1 <имя_графа,номер_билда>] [-o ] [-l] [-i] [-g] [-rct]


-g1 <имя_графа,ключ_билда> - граф для распаковки
-o - файл вывода результатов. Указывать расширение!
-l - декомпиляция level.graph. Из-за неправильного заголовка при декомпиляции level.graph от 1475,1510 неверно
определяется edge_count (начиная с 1834 все нормально). Ориентируйтесь на число секций edge.
-g - выводит список уровней, отсортированных по гейм_вертексу, в отдельный файл guids.txt. Для билдов старше 1849
(24 февраля 2004) также выводятся связи между уровнями. Если не указан - список будет выведен в консоль.
-i - игнорирование левел-поинтов при чтении и выводе. Существенно ускоряет работу программы, советую использовать.
У билдов младше 1472 (включая) левел-поинты в game.graph не содержатся, указывать ключ не надо.
-rct - читать и выводить кросс-таблицы (для ЧН, ЗП). Лучше не пользовать, кросс-таблицы оооочень большие,
читаются долго, а практического толку от них ноль.

Для распаковки графа БОЛЬШЕ НИКАКИХ КЛЮЧЕЙ НЕ УКАЗЫВАТЬ!

Пример: ggrc.pl -g1 game.graph,2215 -o links.txt -g -i

------------------------------------------------------------
--------------------ДОБАВЛЕНИЕ АИ-ПЕРЕХОДОВ-----------------
------------------------------------------------------------

АИ-переходы необходимы для оффлайн-навигации неписей между разными локациями. Выбираете два вертекса,
один на одной локации, второй на другой, соединяете связью - переход для непися готов.

Команда:
ggrc.pl [-g1 <имя_графа,номер_билда>] [-ai ]

-g1 <имя_графа,ключ_билда> - граф для добавления переходов
-ai - соединяемые вертексы, через запятую (без пробелов!).

Пример: ggrc.pl -g1 game.graph,2215 -ai 14,134

На выходе получите файл типа game.graph.new_edge. Это геймграф с готовыми переходами.

Больше ключей не нужно.

-------------------------------------------------------------
Ключи билдов:
1469 - билд 1469
1472 - билд 1472
1510 - билды с датой компиляции от июня 2003 (1475) по первую половину августа 2004 (1902)
1935 - билды с датой компиляции от второй половины августа 2004 (1911) по февраль 2005 (2201)
2215 - билды с датой компиляции от апреля 2005 (2203) по декабрь 2005 (2365)
soc - билды с датой компиляции от начала 2006 по билд 3120.
cop - от ЧН и выше.

-------------------------------------------------------------

История версий:

v.0.7 [+] добавлена правка level.geom/level.geomx при переносе локаций в билды/из билдов
[+] включена коррекция вертексов в кросс-таблицах родительского графа
[+] добавлено сканирование шейдеров, текстур и материалов, используемых подключаемыми локациями и вывод
отсутствующих в лог.

v.0.6 [+] добавлена коррекция вертексов в кросс-таблицах.
[+] добавлена правка версии xrLC в level при переносе локаций в билды/из билдов.

v.0.5 [+] тестово добавлена поддержка билдов 1834-2201.
пофиксен ряд багов,

v.0.4 отключено чтение неизменяемых файлов (родительские level.ai, level.gct, дочерние level.ai, если
версии графов одинаковы)

v.0.3 [+] включена возможность добавления аи-переходов между локациями.

v.0.2 [+] включено восстановление level.graph по game.graph (работает для всех версий, начниная по крайней мере
с 2005 года - более ранние пока не проверял, теоретически тоже должны корректно восстанавливаться).
немного изменен алгоритм коррекции game_vertex_id у связей.

v.0.1 [+] реализован основной функционал (совмещение графов, обновление кросс-таблиц и аи-сетки)
--------------------------------------------------------------
Авторство:
Исходный код распаковки графа финалки ТЧ - bardak (огромное ему спасибо)
Все остальное - K.D.


Описание утилиты, но почитай внимательно тему, что давал по ссылке.

_http://www.amk-team.ru/forum/index.php?showtopic=11568&st=0

отредактировал(а) dimak: 30-01-2013 20:11 GMT3 час.

Как здорово быть тёртым сталкером! Не бояться каждого шороха, оружия не носить с собой много!
voven
    
Посты: 260
Откуда: Москва
Возраст: 27
31-01-2013 12:01 GMT3 час. #1652716   
Strchi Ошибка вылетает при загрузке рисунка xr_3da


dromundus
    
Посты: 143
Откуда: moscow
Возраст:
01-02-2013 01:48 GMT3 час. #1652856   
Кто нибудь знает , что это за дрянь?....

Expression : fatal error
Function : CInifile::r_section
File : E:\stalker\patch_1_0004\xrCore\Xr_ini.cpp
Line : 342
Description :
Arguments : Can't open section '&覇„ &譾&覆„ &襈'


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


Крути "Башней"....
Strchi
    
Посты: 2581
Откуда: Уфа-Челябинск-Фритаун
Возраст:
01-02-2013 08:36 GMT3 час. #1652867   
voven возможны ошибки при начальной загрузке если ошибка в файлах меню (посмотри в config\ui)


Fagot_
    
Посты: 283
Откуда: СССР, Владивосток.
Возраст: 131
01-02-2013 13:36 GMT3 час. #1652905   
Привет! Кто знает, как заспавнить мину (минное поле) ? Так: zone_mine_field не работает, видимо ещё что-то надо...


Я давно хотел вас спросить, как художник художника - вы рисовать умеете?..
Struck
    
Посты: 1946
Откуда:
Возраст:
01-02-2013 13:59 GMT3 час. #1652910   
Fagot_ и почему же не работает? :-)


Снова в строю.

l
Fagot_
    
Посты: 283
Откуда: СССР, Владивосток.
Возраст: 131
01-02-2013 14:21 GMT3 час. #1652913   
Struck , а я знаю? Может, спавнить надо не alife():create , а как-то по другому.

5AX3T-7RYY2-TXVEX-I6XIJ-RT3JY

отредактировал(а) TheDoktor: 13-03-2013 16:47 GMT3 час.

Я давно хотел вас спросить, как художник художника - вы рисовать умеете?..
frankenshtayn
    
Посты: 203
Откуда:
Возраст: 52
01-02-2013 18:49 GMT3 час. #1652937   
Fagot_ Скриптом? Тогда(если не ошибаюсь) - мина это аномалия, нужен нетпакет
Спавн аномалий скриптовым методом без использования all.spawn, а соответственно без необходимости начинать новую игру:

1) Создаём в папке \gamedata\scripts скриптовый файл с любым именем, напрмер, anomaliya_spawn.script и заполняем этот файл следующим содержанием:

function get_story_id_not_replay()
local ST
ST = xr_logic.pstor_retrieve(db.actor, "ScriptAnomId", 0)
if type(ST) ~= "number" or ST == nil then
ST = 9000
xr_logic.pstor_store(db.actor, "ScriptAnomId", ST)
end
if type(ST) == "number" or ST ~= nil then
ST = ST + 1
xr_logic.pstor_store(db.actor, "ScriptAnomId", ST)
end
return tonumber(ST)
end
function create_anom(name_anom, posit_anom, lvid_anom, gvid_anom, radius_anom, power_anom)
local obj = alife():create(name_anom, posit_anom, lvid_anom, gvid_anom)
-----------------------write----------------------
local packet = net_packet()
obj:STATE_Write(packet)
-----------------------load-----------------------
-- cse_alife_object
local game_vertex_id = packet:r_u16()
local distance = packet:r_float()
local direct_control = packet:r_u32()
local level_vertex_id = packet:r_u32()
local object_flags = packet:r_u32()
local custom_data = packet:r_stringZ()
local story_id = packet:r_u32()
local spawn_story_id = packet:r_u32()
-- cse_shape
local shape_count = packet:r_u8()
for i=1,shape_count do
local shape_type = packet:r_u8()
if shape_type == 0 then
-- sphere
local center = packet:r_vec3()
local radius = packet:r_float()
else
-- box
local box = packet:r_matrix()
end
end
-- cse_alife_space_restrictor
local restrictor_type = packet:r_u8()
-- cse_alife_custom_zone
local max_power = packet:r_float()
local owner_id = packet:r_u32()
local enabled_time = packet:r_u32()
local disabled_time = packet:r_u32()
local start_time_shift = packet:r_u32()
-- cse_alife_anomalous_zone
local offline_interactive_radius = packet:r_float()
local artefact_spawn_count = packet:r_u16()
local artefact_position_offset = packet:r_u32()
-- se_zone_anom
local last_spawn_time_present = packet:r_u8()
if (string.find (name_anom, 'zone_zharka_static') ~= nil
or string.find (name_anom, 'zone_witches_galantine') ~= nil
or string.find (name_anom, 'zone_mosquito_bald') ~= nil
or string.find (name_anom, 'zone_mincer') ~= nil
or string.find (name_anom, 'zone_gravi_zone') ~= nil
or string.find (name_anom, 'zone_buzz') ~= nil )
and packet:r_elapsed() ~= 0 then
abort("left=%d", left)
end
---------------------------save--------------------
-- cse_alife_object
packet:w_begin(game_vertex_id)
packet:w_float(distance)
packet:w_u32(direct_control)
packet:w_u32(level_vertex_id)
obj ect_flags = bit_not(193)
packet:w_u32(object_flags)
packet:w_stringZ(custom_data)
packet:w_u32(get_story_id_not_replay())
packet:w_u32(get_story_id_ not_replay())
-- cse_shape
packet:w_u8(1) -- количество фигур
packet:w_u8(0) -- тип фигуры: сфера
packet:w_vec3(vector():set(0, 0, 0))
if radius_anom ~= nil then
packet:w_float(radius_anom)
else
packet:w_float(1.0)
end
-- cse_alife_space_restrictor
packet:w_u8(restrictor_type)
-- cse_alife_custom_zone
if power_anom ~= nil then
packet:w_float(power_anom)
else
packet:w_float(max_power)
end
packet:w_u32(owner_id)
packet:w_u32(enabled_time)
packet:w_u32(dis abled_time)
packet:w_u32(start_time_shift)
-- cse_alife_anomalous_zone
packet:w_float(offline_interactive_radius)
packet:w_u16(artefact_spawn_count)
packet:w_u32(artefact_position_off set)
-- se_zone_anom
packet:w_u8(last_spawn_time_present)
------------------------read------------------------
packet:r_seek(0)
obj:STATE_Read (packet, packet:w_tell())
end
-----------------------------------спавним аномалии-----------------------------------
function spawn_anom1()
this.create_anom('zone_zharka_static', vector():set(-30.974,0.002,693.734),178968,2618, 3, 0.7)
end
function spawn_anom2()
this.create_anom('zone_witches_galantine_strong', vector():set(-20.851,0.000,693.588),178968,2618, 5, 0.8)
end
function spawn_anom3()
this.create_anom('zone_mincer_average', vector():set(-26.064,0.000,698.637),178968,2618, 4, 1)
end
--Последние две цифры после координат - это радиус действия аномалии и её сила соответственно.

2) Всё, теперь остаётся вызвать функции спавна из диалога или из инфопоршня и три наши аномалии заспавнятся на заданных координатах в нужный игровой момент.

попробуй.


И ЭТО ПРОЙДЕТ...
Struck
    
Посты: 1946
Откуда:
Возраст:
01-02-2013 19:11 GMT3 час. #1652942   
Fagot_ :sarcastic: с этого бы и начинал(учись задавать вопросы, чтобы не отвечать вопросом на вопрос), мина, это что-то вроде аномалии, и спавнится она через all.spawn, либо с помощью нетпакетов, как тебе и указал frankenshtayn.


Снова в строю.

l
Kentarius
    
Посты: 40
Откуда: Flensburg
Возраст:
01-02-2013 20:19 GMT3 час. #1652951   
возник вот такой вопрос, уже долго мучаюсь и никак не могу сделать ГГ героя более уязвимей к огнестрельному оружию, чем уже есть! то есть мне хотелось бы сделать так, чтоб практически от каждого выстрела ГГ получал либо критический урон или умирал! чтоб не ходить терминатором по зоне. уже просто тупо идешь штурмом на блок пост на кордоне и всех там выносишь, на АТП бандиты стреляют в упор и только иногда из дробовика бывает случайно выносят!
я сделал следующие:
ну во-первых повысил урон всех оружий, но теперь и я сам даже если попадаю в мизинец на ноге какого-нибудь непися то он сразу гибнет!
во вторых я поднял вероятность попадания неписями в ГГ.
damage = actor_damage

hit_probability_gd_novice = 2.0
hit_probability_gd_stalker = 3.0
hit_probability_gd_veteran = 4.0
hit_probability_gd_master = 5.0

не знаю на сколько это правильно но в принципе существенной разнице я не заметил!
потом я понизил иммунитет к ранам и от огнестрельных оружий у ГГ.
wound_immunity = 0.1
fire_wound_immunity = 0.1

ну и поднял урон ГГ
default = 2.0, -1, 3.0

bip01_head = 2, 0, 3.0
eyelid_1 = 2, 0, 3.0
eye_left = 2, 0, 3.0
eye_right = 2, 0, 3.0
jaw_1 = 2, 0, 3.0

bip01_pelvis = 2.0, 10, 3.0
bip01_spine = 2.0, 10, 3.0
bip01_spine1 = 2.0, 0, 3.0
bip01_spine2 = 2.0, 0, 3.0
bip01_neck = 2.0, 0, 3.0


bip01_l_clavicle = 2.0, 4, 3.0
bip01_l_upperarm = 2.0, 4, 3.0
bip01_l_forearm = 2.0, 4, 3.0
bip01_l_hand = 2.0, 4, 3.0

bip01_r_clavicle = 2.0, 2, 3.0
bip01_r_upperarm = 2.0, 2, 3.0
bip01_r_forearm = 2.0, 2, 3.0
bip01_r_hand = 2.0, 2, 3.0

bip01_l_thigh = 2.0, 8, 3.0
bip01_l_calf = 2.0, 8, 3.0
bip01_l_foot = 2.0, 8, 3.0
bip01_l_toe0 = 2.0, 8, 3.0
bip01_r_thigh = 2.0, 6, 3.0
bip01_r_calf = 2.0, 6, 3.0
bip01_r_foot = 2.0, 6, 3.0
bip01_r_toe0 = 2.0, 6, 3.0

и все равно блин без единого сохранения и с одной аптечкой всех выношу на блокпосту и на АТП.

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


Strchi
    
Посты: 2581
Откуда: Уфа-Челябинск-Фритаун
Возраст:
01-02-2013 22:19 GMT3 час. #1652965   

# Kentarius :


hit_probability_gd_novice = 2.0
hit_probability_gd_stalker = 3.0
hit_probability_gd_veteran = 4.0
hit_probability_gd_master = 5.0



Вот это и есть уязвимость ГГ на разной сложности...


Kentarius
    
Посты: 40
Откуда: Flensburg
Возраст:
01-02-2013 22:27 GMT3 час. #1652966   
да, но я играю на мастере а неписи как не умели стрелять так и не могут, и все равно сколько я там ставлю 1.0 или 5.0 может есть еще где можно что нибудь подкрутить?


Fagot_
    
Посты: 283
Откуда: СССР, Владивосток.
Возраст: 131
02-02-2013 05:20 GMT3 час. #1652988   
Kentarius , если не ошибаюсь, эти

hit_probability_gd_novice = 0.70
hit_probability_gd_stalker = 0.80
hit_probability_gd_veteran = 0.85
hit_probability_gd_master = 0.95
параметры необходимо выставлять от 0.0 до 0.1, т.е. 0.95 - это 95% попаданий по ГГ. И ещё, поиграйся с [actor_damage] , как ты и делал, в частности с параметрами bip... и т.п. Может, ты не до конца с ними разобрался. Там урон, наносимый по разным частям тела. И тебе надо было не только убойность стволов повышать, можно ещё такую штуку сделать: задрать убойность бронебойных патронов и раздать их сталкерам, а самому пользоваться простыми (при необходимости снизив их убойность).

Frankenstein,
спасибо.


добавлено спустя 2 часа 38 минут

frankenshtayn , попробовал - не спавнятся мины... Ты сам делал таким способом, у тебя спавн нормально происходит?

отредактировал(а) Fagot_: 03-02-2013 03:03 GMT3 час.

Я давно хотел вас спросить, как художник художника - вы рисовать умеете?..
Molotov Bahtiyar
    
Посты: 8
Откуда: Алматы
Возраст:
02-02-2013 20:39 GMT3 час. #1653089   
Это вам ребятя не мучайтесь:
1.Улучшение аи NPC

Для того, чтобы НПС лечились сами, заходим в gamedata\scripts\xr_wounded. Находим строки xr_logic.pstor_retrieve(self.object, "wounded_fight") и заменяем false на true. Поступаем так во всех таких стоках. Их там 2.Далее в if self.object:critically_wounded() ставим true (вроде здесь..). Тоже несколько раз. В if wound_manager_state тоже самое.(или здесь...) Самое главное if self.a.use_medkit тоже самое. Тепеоь НПС будут лечиться сами, но аптечек у них практически нет. Дело в том, что когда мы обыскиваем тела, то видим аптечки. Их инвенарь делиться на три части: собираем с трупов, торгуем, то что есть на самом дел. Нам нужно последнее. Для этого заходим в gamedata\config\gameplay \character_desc_ (!!!)_где (!!!) название локации. И у нужно го персонажа в разделе [spawn] пишем: medkit \n.

Все! Готово!
2.Как видно, этот способ решения проблем не подходит для шутера, так как ситуация в игре может меняться непредсказуемым образом и построенный план решения (последовательность операторов) станет неприменимым к текущей ситуации. Поэтому планировщик запускается каждый раз при непредвиденном развитии событий и создаёт новую последовательность действий (операторов).
Условия в игре тоже вычисляются динамически. Для этого используются специальные объекты – эвалуаторы. Эвалуатор должен содержать метод evaluate(), возвращающий true, если условие выполняется и false в противном случае. Операторы также представлены как объекты. Планировщик вызывает метод initialize() при начале работы оператора, затем он периодически вызывает метод execute().
Например, можно создать эвалуатор для условия «NPC голоден», и привязать к этому условию оператор «поесть».
Планировщик будет периодически проверять это условие (вызывать метод evaluate() эвалуатора), и если оно выполняется, инициализирует и будет выполнять оператор «поесть» до тех пор, пока условие не станет ложным.
К сожалению, в большей части скриптов все возможности планировщика не используются.
[править]Разбор настройки и работы планировщика на примере скрипта xr_kamp
Рассмотрим скрипт xr_kamp, заставляющий сталкеров сидеть у костра и рассказывать анекдоты. Настройка планировщика осуществляется в функции add_to_binder. Параметры функции: object – объект для которого настраивается планировщик (в нашем случае это сталкер), ini, scheme, section – инициализационный файл, название схемы действий, секция ини-файла (эти параметры будут подробно разобраны в части по созданию мода), storage – таблица для хранения текущих параметров схемы действий.
Разберём, что делает эта функция.
Сначала получаем планировщик для текущего объекта (object).
local manager = object:motivation_action_manager()
Затем присваиваем идентификаторы операторов и условий элементам массива. Это сделано просто для удобства.
Идентификаторы могут иметь любое целочисленное значение, главное, чтобы они были уникальными, то есть не использовались для других операторов и условий.
properties["kamp_end"]=xr_evaluators_id.stohe_kamp_base+1
properties["on_position"]=xr_evaluators_id.stohe_kamp_base+2
properties["contact"]=xr_evaluators_id.stohe_meet_base+1
operators["go_position"]=xr_actions_id.stohe_kamp_base+1
operators["wait"]=xr_actions_id.stohe_kamp_base+3
Для каждого идентификатора условия создадим соответствующий эвалуатор и добавим его в планировщик. В данном случае это условия: «закончить ли посиделки около костра?» и «пришёл ли я на своё место у костра?»
manager:add_evaluator (properties["kamp_end"],
this.evaluator_kamp_end ("kamp_end", storage, "kamp_end"))manager:add_evaluator (properties["on_position"],
this.evaluator_on_position ("kamp_on_position", storage, "kamp_on_position"))
Теперь создадим оператор «сидеть около костра, рассказывать анекдоты, жевать колбасу и т.д.». Можно было бы реализовать эти действия как набор разных операторов, выбором которых занимался бы планировщик, но автор скрипта решил сделать один сложный оператор.
local action = this.action_wait (object:name(),"action_kamp_wait", storage)
Задаем предусловия для этого оператора. Планировщик выберет этот оператор при выполнении всех условий. Всё это значит примерно следующее: я могу сидеть у костра, если:
action:add_precondition (world_property(stalker_ids.property_alive, true))
я живой,
action:add_precondition (world_property(stalker_ids.property_danger,false))
опасностей нет,
action:add_precondition (world_property(stalker_ids.property_enemy, false))
врагов нет,
action:add_precondition (world_property(stalker_ids.property_anomaly,false))
аномалий поблизости нет,
xr_motivator.addCommonPrecondition(action)
выполняются другие важные условия (игрок не собирается со мной поговорить, я не собираюсь никого бить по морде, я не ранен, я не собираюсь стрелять по вертолёту),
action:add_precondition (world_property(properties["on_position"], true))
я уже нахожусь около костра.
Скажем планировщику, что он должен ожидать от выполнения этого оператора. В данном случае после выполнения этого оператора условие «закончить ли посиделки около костра?» должно стать истинным. То есть если условие стало истинным, планировщик прекратит выполнение оператора.
action:add_effect (world_property(properties["kamp_end"], true))
Создание оператора завершено. Добавим его в планировщик.
manager:add_action (operators["wait"], action)
Эта строчка не имеет отношения к работе планировщика. Если коротко, то она позволяет объекту получать уведомления об определённых событиях (смерть NPC – вызывается метод death_callback(), попадание пули в NPC – вызывается метод hit_callback() и т.д.)
xr_logic.subscribe_action_for_events(object, storage, action)
Создаем оператор, отвечающий за доставку NPC к его месту у костра.
action = this.action_go_position (object:name(),"action_go_kamp", storage)
Добавляем предусловия, как и для предыдущего оператора.
action:add_precondition (world_property(stalker_ids.property_alive, true))
action:add_precondition (world_property(stalker_ids.property_danger,false))
action:add_precondition (world_property(stalker_ids.property_enemy, false))
action:add_precondition (world_property(stalker_ids.property_anomaly,false))
xr_motivator.addCommonPrecondition(action)
action:add_precondition (world_property(properties["on_position"], false))
Единственное отличие – последнее условие. Этот оператор будет выполняться только если NPC ещё не находится на своем месте у костра, то есть если функция evaluator_on_position.evaluate() возвращает false.
В результате выполнения этого действия условие «на своём ли я месте у костра?» должно стать истинным.
action:add_effect (world_property(properties["on_position"], true))
Создание оператора завершено. Добавляем его к планировщику.
manager:add_action (operators["go_position"], action)
Осталось ещё одна задача. Нужно запретить планировщику активировать оператор «alife», тот самый оператор, который заставляет NPC болтаться по карте, отстреливать собачек и в конце концов попадать в аномалию. Впрочем, отстрелом врагов занимается другой оператор с идентификатором stalker_ids.action_combat_planner.
Для этого мы получаем оператор «alife»
action = manager:action (xr_actions_id.alife)
И добавляем к его предусловиям следующее: условие «закончить ли посиделки у костра?» должно быть истинным.
action:add_precondition (world_property(properties["kamp_end"], true))
Итак, мы настроили планировщик. Посмотрим как всё это будет работать.
В некоторый момент времени гулаг, в который попал NPC, назначает ему работу: сидеть у костра. В результате условие «закончить ли посиделки у костра?» становится ложным. Планировщик видит это изменение и пытается выработать последовательность операторов, после выполнения которой, условие бы стало истинным и NPC снова бы вернулся к выполнению высокоприоритетного оператора «alife». Для выполнения этой задачи подходит оператор «посиделки у костра», но для него не выполняется условие «я на своем месте у костра». Поэтому планировщик создаёт план из двух операторов: «дойти до костра» и «посиделки у костра». Если во время выполнения одного из операторов возникнет непредвиденная ситуация (появится враг, главный герой начнёт приставать с вопросами и т.п.), то планировщик скорректирует план, добавив оператор для устранения этой непредвиденной ситуации.
Как видно система ИИ в Сталкере обладает весьма большой гибкостью, что мы и продемонстрируем при создании мода.
[править]Модели (или схемы) поведения в Сталкере

В наборе скриптов Сталкера предусмотрена возможность объединять операторы и условия в модели поведения. Модель поведения – это набор логически связанных операторов и условий, служащих для выполнения определённой задачи. Так скрипт xr_kamp представляет собой модель поведения, состоящую из двух операторов и двух условий.
[править]Регистрация модели поведения
Для включения новой модели поведения в набор моделей, доступных NPC, сначала необходимо её зарегистрировать. Предположим, нам нужно зарегистрировать модель поведения, описанную в скрипте actor_need_help.script. Регистрация моделей осуществляется в скрипте modules.script. Добавим туда следующие строки:
if actor_need_help then – в этой строке мы проверяем что наш скрипт действительно существует
load_scheme("actor_need_help", "actor_need_help", stype_stalker)
end
Первый параметр функции load_scheme задает имя файла скрипта, второй параметр – это название модели поведения, третий параметр – тип модели поведения (возможны следующие значения: stype_stalker – модель поведения NPC, stype_mobile – модель поведения монстра, stype_item – «модель поведения» физического объекта, stype_heli – модель поведения вертолёта, stype_restrictor – «модель поведения» области пространства). Скрипты для моделей поведения разных типов пишутся по-разному. Мы будем рассматривать только модели поведения NPC.
Внимание! Для успешной работы модели поведения её скрипт должен содержать функцию add_to_binder, выполняющую настройку планировщика.
[править]Активация/деактивация модели поведения
Некоторые модели поведения применимы в любых ситуациях (например, реакция на попадание пули в NPC или реакция на появление врага). Такие модели должны активироваться/деактивироваться в функциях
enable_generic_schemes()/disable_generic_schemes() скрипта xr_logic. В случае с моделью поведения actor_need_help,
это будет выглядеть так:
1. Создаём функции set_actor_need_help и disable_scheme в нашем скрипте actor_need_help. Эти функции будут отвечать за активацию и деактивацию нашей модели поведения.
function set_actor_need_help(npc,ini,scheme)
local st=xr_logic.assign_storage_and_bind(npc, ini, scheme, “actor_need_help”)
st.enabled=true
end
function disable_scheme(npc,scheme)
local st = db.storage[npc:id()][scheme]
if st then
st.enabled = false
end
end
2. Добавляем следующую строку в скрипт xr_logic.script после строки «if stype == modules.stype_stalker then» в функции enable_generic_schemes()
actor_need_help.set_actor_need_help(npc,ini,”actor_need_help”)
3. Добавляем следующую строку в скрипт xr_logic.script после строки «if stype == modules.stype_stalker then» в функции disable_generic_schemes()
actor_need_help.disable_scheme(npc,”actor_need_help”)
Если же модель поведения предназначена только для использования в определённых ситуациях, то достаточно выполнить шаг 1 и использовать созданные функции по мере надобности. Например, активируя эту схему через диалог с NPC (как мы и сделаем в нашем моде).
Внимание! Я максимально упростил функции активации/деактивации модели поведения. Чтобы полностью разобраться с ними, посмотрите скрипты xr_combat, xr_kamp и другие подобные.
[править]Приоритеты моделей поведения
Некоторые модели поведения настолько важны, что должны срабатывать в любой ситуации (например, реакция на попадание пули). Для этого в скрипте xr_motivator предусмотрена функция addCommonPrecondition(action), в эту функцию можно добавить одно из условий нашей модели поведения, чтобы другие модели поведения не могли сработать при выполнении этого условия (здесь есть свои тонкости, но мы рассмотрим их позже). Предположим, что у нас есть модель поведения actor_need_help, заставляющая NPC подбежать к ГГ и вылечить его. Пусть за проверку здоровья ГГ отвечает условие с идентификатором actor_need_help.property_actor_is_wounded. Значит, если мы хотим, чтобы NPC подбегал к ГГ не обращая внимание ни на что другое, то нужно добавить следующую строчку в функцию addCommonPrecondition(action):
action:add_precondition(world_property(actor_need_help.property_actor_is_wounded,false))
Эта строчка запретит выполнение всех других действий, если условие с идентификатором actor_need_help.property_actor_is_wounded станет истинным (в нашем случае это будет означать, что ГГ сильно ранен.
Конкретное значение здоровья ГГ при котором он считается сильно раненным будет определять эвалуатор этого условия).

[править]Создаем мод

В этом разделе мы сделаем мод, позволяющий сказать дружественно настроенному NPC, чтобы он лечил главного героя во время боя.
[править]Постановка задачи

Итак, мы хотим, чтобы дружественные NPC наконец начали приносить пользу. Для этого научим их лечить ГГ во время боя. Распишем по пунктам:
1. Нужно добавить дружественным NPC ветку в диалоге с просьбой присматривать за ГГ и лечить его, если в этом возникнет необходимость.
2. Добавить NPC модель поведения, реализующую выполнение этой просьбы.
2.1. NPC должен действовать согласно этой модели только если ГГ находится недалеко от него.
2.2. NPC не должен далеко отходить от ГГ во время боя.
2.3. Если здоровье ГГ упало ниже определённой отметки, NPC должен подойти/подбежать и вылечить ГГ.
[править]Что потребуется для реализации

Нам придётся изменять диалоги для некоторых NPC, для этого нужно будет изменить файлы config\gameplay\character_dialogs.xml (диалоги для всех NPC), config\localization.ltx и config\system.ltx (подробнее см. статью BAC9-FLCL или Fr3nzy). Мы изменим диалоги для всех NPC, но для неподходящих NPC диалог будет отсекаться с помощью предусловия. Потребуется также добавить файлы с текстами диалогов и функции для проверки условий, используемых в диалогах.
Для включения новой модели поведения NPC нужно будет внести изменения в скрипты scripts\modules.script (регистрация моделей поведения) и scripts\xr_motivator.script (для установки высокого приоритета нашей модели). Модификации файла xr_logic.script, в котором происходит установка общих моделей поведения, не потребуется, так как мы будем активировать нашу схему поведения при выборе определённой ветки в диалоге.
Теперь решим какие условия и операторы нам понадобятся.
Условия:
1. Состояние главного героя. Если оно ниже определённого порога, то условие станет истинным. Назначим ему идентификатор property_actor_is_wounded и эвалуатор evaluator_actor_is_wounded. Далее я буду указывать идентификатор и эвалуатор в скобках через запятую.
2. Находится ли NPC достаточно близко, чтобы вылечить ГГ. (property_ready_to_heal, evaluator_ready_to_heal)
3. Есть ли у NPC аптечки. (property_has_medkit, evaluator_has_medkit)
4. Не отошёл ли NPC слишком далеко от ГГ или ГГ от NPC. (property_faraway, evaluator_faraway)
5. Находится ли ГГ достаточно близко, чтобы имело смысл помогать ему. (property_near_enough, evaluator_near_enough).
Операторы:
1. Лечить ГГ. (act_heal, action_heal)
2. Подбежать к ГГ на дистанцию, достаточную для лечения (act_run_to_actor, action_run_to_actor)
3. Крикнуть что аптечки кончились (act_no_medkit, action_no_medkit)
4. Подобраться поближе к ГГ, чтобы быть под рукой. (act_stay_close, action_stay_close).
[править]Реализация

Я буду писать эту статью параллельно с разработкой мода, указывая все найденные ошибки. Надеюсь, это поможет другим моддерам. Чтобы отделить результаты тестирования от описания процесса разработки мода, я буду выделять свои комментарии другим шрифтом.
[править]Диалоги
В этом моде будет всего один диалог, и довольно простой, поэтому начнём с него. Создаём файл config\gameplay\dialogs_need_help.xml. Чтобы не возиться с идентификаторами текстов попробуем обойтись без них. Начнём с простой тестовой версии:



actor_need_help.i_am_friend


Дружище, сможешь присмотреть за мной, если стрелять начнут? Промедольчику, там, вколоть или

перевязку сделать, если что...

1


Нет проблем, конечно помогу.




Добавляем строку с идентификатором этого диалога в config\gameplay\character_dialogs.xml:
actor_will_need_help
Дописываем имя файла диалога в config\system.ltx в секцию «dialogs». Осталось создать функцию i_am_friend. Наш скрипт с моделью поведения будет называться scripts\actor_need_help.script, заодно пропишем там и диалоговые функции.
function i_am_friend(actor,npc)
return npc:relation(actor)==game_object.friend
end
При первом тестировании я заменил game_object.friend на game_object.neutral, чтобы не искать друзей по всей карте.
Тестируем, что у нас получилось...
Диалог работает, но вместо текста – набор значков, оказалось, я написал текст в кодировке CP866 (DOS), нужно поменять её на CP1251. Так, теперь текст в порядке.
Выбранный подход к созданию диалога оказался удачным.
Обратите внимание, вместо идентификатора текста можно вписать сам текст. Это усложнит локализацию, но уменьшит время создания диалогов.
Теперь нам понадобятся функции проверки наличия аптечек у NPC, проверки активации схемы поведения, активации/деактивации схемы поведения. Добавляем их в наш скрипт-файл.
Первый вариант скрипта я не буду приводить, чтобы не увеличивать и так большую статью. Окончательный вариант смотрите в конце статьи. Дальше по тексту идёт простейший работающий вариант.
Теперь у нас должно быть два варианта начальной фразы для активной и неактивной схемы. Придётся экспериментировать.
'Вот первый проверенный вариант:



actor_need_help.i_am_friend


1
2


Дружище, сможешь присмотреть за мной, если стрелять начнут? Промедольчику, там, вколоть или

перевязку сделать, если что...

actor_need_help.scheme_is_not_active
11
12


Нет проблем, конечно помогу.
actor_need_help.npc_have_medkit
actor_need_help.activate_scheme


Извини, друг, аптечек совсем не осталось.
actor_need_help.npc_havent_medkit


Спасибо, друг, теперь я сам справлюсь.
actor_need_help.scheme_is_active
21


Да не за что, ты мне помог, я - тебе.
actor_need_help.deactivate_scheme




При первом запуске игра вылетела без сообщений об ошибках. Я внимательно просмотрел все файлы и оказалось, что в скриптах вместо комментария ‘--‘ (два минуса) я поставил просто минус (рекомендую пользоваться компилятором с [www.lua.org www.lua.org] для проверки корректности скриптов). После исправления ошибки игра запустилась, но диалог так и не появился. Небольшая дискуссия на форуме (спасибо Z.E.N. и Arhet) показала, что придётся сделать два диалога.
Кроме того, при тестах первых вариантов, выяснилось, что всегда выбирается вариант диалога с просьбой о помощи. То есть схема поведения не активируется.
Как оказалось, в качестве параметров в функции передаются не объекты ГГ и NPC, а объекты говорящего в данный момент персонажа и его собеседника. То есть, если фраза принадлежит NPC, то первый параметр будет объектом для NPC, а не для ГГ. Поэтому я изменил названия параметров и переписал функции.
Итак, все проблемы решены. Файл диалога принял следующий вид (config\gameplay\dialogs_need_help.xml):



actor_need_help.i_am_friend
actor_need_help.scheme_is_not_active


Дружище, сможешь присмотреть за мной, если стрелять начнут? Промедольчику, там, вколоть или

перевязку сделать, если что...

11
12


actor_need_help.npc_have_medkit
Нет проблем, конечно помогу.
actor_need_help.activate_scheme


actor_need_help.npc_havent_medkit
Извини, друг, аптечек совсем не осталось.




actor_need_help.i_am_friend
actor_need_help.scheme_is_active


Спасибо, друг, теперь я сам справлюсь.
21


Да не за что, ты мне помог, я - тебе.
actor_need_help.deactivate_scheme




Функции, поддерживающие работу диалога, теперь выглядят так (файл scripts\actor_need_help.script):
function i_am_friend(talker,target)
return target:relation(talker)==game_object.friend
end

-- За основу этой функции взята функция dialogs.actor_have_medkit
function npc_have_medkit(talker, target)
return talker:object("medkit") ~= nil or
talker:object("medkit_army") ~= nil or
talker:object("medkit_scientic") ~= nil
end
function npc_havent_medkit(talker, target)
return not npc_have_medkit(talker,target)
end

-- Так как модель поведения еще не написана, вставим заглушки
local scheme_status={}
function scheme_is_active(talker,target)
return scheme_status[target:id()]==true -- сравниваем с true, чтобы функция не возвращала nil
end
function scheme_is_not_active(talker,target)
return not scheme_is_active(talker,target)
end
function activate_scheme(talker,target)
scheme_status[talker:id()]=true
end
function deactivate_scheme(talker,target)
scheme_status[talker:id()]=nil -- присваиваем nil, чтобы освободить память, занятую этим элементом массива
end
И в файл config\gameplay\character_dialogs.xml добавлены строки:
actor_will_need_help
actor_will_not_need_help
В результате получился работающий диалог, но NPC выглядит просто как ходячая аптечка. В окончательном варианте, я добавил некоторые «человеческие» реакции. Да и сама модель поведения пока отсутствует - вместо неё стоят заглушки. Исправим это.
[править]Модель поведения
Начнём создание модели поведения с разработки эвалуаторов. Эвалуатор должен представлять собой объект класса унаследованного от класса property_evaluator.
Возьмём для начала эвалуатор evaluator_faraway определяющий, что NPC находится слишком далеко от ГГ. Этот эвалуатор требуется для того, чтобы NPC не отходил слишком далеко от ГГ и мог в случае надобности быстро подбежать к нему и оказать помощь.
Объявляем класс эвалуатора:
class "evaluator_faraway" (property_evaluator)
Определяем функцию инициализации (в LUA это аналог конструктора объекта)
function evaluator_faraway:__init(name, storage) super (nil, name)
self.st = storage
end
Ключевое слово «super» служит для вызова конструктора базового класса. Член «st» будет хранить ссылку на таблицу состояния нашей модели поведения.
Теперь нужно определить функцию evaluate(), ради которой и создавался эвалуатор. По-видимому всё просто, нужно проверить расстояние от NPC до ГГ и вернуть true, если это расстояние больше определённого значения. Но давайте подумаем. Когда эвалуатор возвратит true, заработает оператор, заставляющий NPC подойти поближе к ГГ, то есть расстояние моментально уменьшится и эвалуатор начнёт возвращать false, что приведёт к переходу NPC под управление игрового ИИ. ИИ может опять решить удалиться от ГГ, что приведёт к повторному срабатыванию эвалуатора. В результате возникнет замкнутый цикл, и NPC будет крутиться на одном месте (на самом деле этот цикл рано или поздно разорвётся из-за изменения игровой ситуации, но лучше вообще избежать его).
Можно использовать разные пути для решения этой проблемы. Попробуем сделать так: будем использовать два расстояния, эвалуатор сработает при достижении первого и будет оставаться активным, пока расстояние не станет меньше второго.
local min_faraway_dist=10
local max_faraway_dist=20

function evaluator_faraway:evaluate()
local actor=db.actor
if not actor then
-- ГГ ещё не заспаунился
return false
end
local dist=actor:position():distance_to(self.object:position())
if dist>max_faraway_dist then
self.st.faraway=true
elseif dist self.st.faraway=false
end
return self.st.faraway==true
end
Эвалуатор готов, но нужно как-то его протестировать. Поэтому давайте создадим минимальную модель поведения из одного условия и одного оператора. Нам нужен оператор, перемещающий NPC поближе к ГГ. Объявляем класс action_stay_close, унаследованный от action_base, и определяем его конструктор.
class "action_stay_close" (action_base)

function action_stay_close:__init(name, storage) super (nil, name)
self.st=storage
end
Оператор должен содержать функции initialize(), execute() и, возможно, finalize().
Функция initialize() вызывается при начала работы оператора, то есть в момент, когда планировщик ставит этот оператор в первую позицию плана.
function action_stay_close:initialize()
local npc=self.object
-- Не знаю зачем эти две функции, но они используются во всех операторах
npc:set_desired_position()
npc:set_desired_direction()
-- Сбрасываем текущие анимации
npc:clear_animations()
-- Задаём параметры движения
npc:set_detail_path_type(move.line)
npc:set_body_state(move.standing)
npc:set_movement_type(move.run)
npc:set_path_type(game_ob ject.level_path)
-- Эксперименты показали, что эта функция устанавливает скорость движения (anim.danger -
минимальная скорость, anim.free - нормальная, anim.panic - максимальная)
npc:set_mental_state(anim.panic)
-- Повышаем зоркость NPC
npc:set_sight(look.danger, nil, 0)
-- Освободим сталкера от всех идиотских ограничений
npc:remove_all_restrictions()
-- Зададим смещение точки назначения, чтобы помощники не сбивались в кучу
self.offset=vector():set(math.random()*6-3,0,math.random()*6-3)
self.offset:normalize()
end
Функция execute() периодически вызывается во время выполнения оператора. Частота вызовов, по-видимому, зависит от расстояния от NPC до ГГ.
function action_stay_close:execute()
local npc=self.object
local actor=db.actor
if not actor then
-- Хм, что-то не так. Может быть ГГ перешёл на другой уровень? Запрещаем схему поведения
self.st.enabled=false
end
-- Получаем ближайшую доступную точку в 5 метрах от ГГ
-- Сначала, я попробавал использовать функцию npc:vertex_in_direction, но она не работает
local vertex_id=level.vertex_in_direction(actor:level_vertex_id(),self.offset,5)
local act_v_id=actor:level_vertex_id()
-- Отправляем нашего NPC в найденную точку
local acc_id=utils.send_to_nearest_accessible_vertex( npc, vertex_id )
if self.st.dist and self.st.dist>max_faraway_dist then
-- если NPC находится слишком далеко от ГГ пусть пробежиться побыстрее
npc:set_mental_state(anim.panic)
else
npc:set_mental_state(anim.free)
end
end
Функция настройки планировщика.
function add_to_binder(object, char_ini, scheme, section, st)
local manager = object:motivation_action_manager()
local property_wounded = xr_evaluators_id.sidor_wounded_base

-- Удаляем эвалуатор, так как в xr_motivator мы установили его в property_evaluator_const
manager:remove_evaluator(property_faraway)
-- и заменяем его нашим
manager:add_evaluator(property_faraway, evaluator_faraway("evaluator_faraway",st))
-- Создаём оператор
local action = action_stay_close("action_stay_close",st)
-- и настраиваем предусловия. 1. Сталкер жив
action:add_precondition(world_property(stalker_ids.property_alive, true))
-- 2. Сталкер не ранен
action:add_precondition(world_property(property_wounded, false))
-- Я использую свой мод для обхода аномалий, иначе от помощников мало толку.
if anomaly_evader then
-- 3. Рядом нет аномалий
action:add_precondition (world_property(1099,false))
end
-- 4. Сталкер слишком далеко от ГГ
action:add_precondition(world_property(property_faraway, true))
action:add_effect (world_property(property_faraway, false))
-- Добавляем оператор в планировшик
manager:add_action (act_stay_close, action)
-- Теперь подкорректируем стандартные операторы, чтобы помощник не отвлекался на всякую ерунду.
action=manager:action(stalker_ids.action_alife_planner)
action:add_precondition(world_property(property_faraway, false))
action=manager:action(stalker_ids.action_combat_planner)
action:add_precondition(world_property(property_faraway, false))
action=manager:action(stalker_ids.action_danger_planner)
action:add_precondition(world_property(property_faraway, false))
end
Добавим функции активации/деактивации схемы поведения.
function set_help(npc, ini)
local st = xr_logic.assign_storage_and_bind(npc, ini, "actor_need_help")
st.enabled=true
end
function disable_scheme(npc, scheme)
local st = db.storage[npc:id()][scheme]
if st then
st.enabled = false
end
end
Изменим диалоговые функции-заглушки.
function activate_scheme(talker,target)
set_help(talker,talker:spawn_ini())
scheme_status[talker:id()]=true
end
function deactivate_scheme(talker,target)
disable_scheme(talker,"actor_need_help")
scheme_status[talker:id()]=nil
end
Добавим в функцию xr_motivator.addCommonPrecondition() следующие строки, чтобы заблокировать стандартные схемы поведения.
if actor_need_help then
action:add_precondition (world_property(actor_need_help.property_faraway,false))
end
Если попробовать запустить мод сейчас, то игра просто вылетит. Причина в том, что мы добавили предусловие для стандартных схем поведения, но не добавили эвалуатор этого условия. Поэтому добавляем в функцию xr_motivator.net_spawn() следующие строки:
local manager = self.object:motivation_action_manager()
if actor_need_help then
manager:add_evaluator(actor_need_help.property_faraway, property_evaluator_const(false))
end
Для того чтобы снизить нагрузку на процессор, используем property_evaluator_const, который всегда возвращает одно и тоже значение. В результате тестирования выяснилось, что не все NPC подчиняются нашей схеме поведения. Причины этого пока не ясны, требуется дополнительное тестирование и очень желательна помощь разработчиков (хотя бы для того чтобы узнать как выяснить какой оператор действует в данный момент на NPC).
[править]Файлы мода
Мод можно скачать здесь.
Ссылка обновлена. Выложена новая версия. Причиной "зависаний" NPC был конфликт со state_mgr.script. Код мода, приведённый в статье, не устанавливал состояние NPC с помощью state_mgr.set_state(), в результате state_mgr пытался вернуть состояние NPC к начальному (до срабатывания нашей модели поведения), что и приводило к "зависаниям"
Большие тексты - под спойлер. Модератор.

отредактировал(а) TheDoktor: 02-02-2013 20:46 GMT3 час.

Strchi
    
Посты: 2581
Откуда: Уфа-Челябинск-Фритаун
Возраст:
02-02-2013 20:51 GMT3 час. #1653092   
Kentarius hit_probability_gd_master = 5.0 можешь хоть на 7.0 будет гораздо сложней


Molotov Bahtiyar
    
Посты: 8
Откуда: Алматы
Возраст:
02-02-2013 20:55 GMT3 час. #1653093   
Уверен Strchi

добавлено спустя 1 минуту

А не легче будет в конфигах сделать чтобы мастера носили гауусы а новички валлы

добавлено спустя 1 минуту

Кто из вас уже играл крутую модификацию на игру Сталкер зп называется Путь в Припять

добавлено спустя 2 минут

Ребят игру сталкер Тч можно пройти за 10 минут легко и просто))

отредактировал(а) Molotov Bahtiyar: 02-02-2013 21:01 GMT3 час.

Fagot_
    
Посты: 283
Откуда: СССР, Владивосток.
Возраст: 131
03-02-2013 02:48 GMT3 час. #1653117   
Molotov Bahtiyar, спасибо тебе большое за скопированный с другого сайта и вставленый сюда текст урока. Я, да и другие тоже,наверно, никогда ещё не видили его...149 раз не видили... А раздать новичкам "валлы" - это да... Это сильно! И ещё, знаешь, иногда надо пользоваться знаками препинания.

отредактировал(а) Fagot_: 03-02-2013 02:52 GMT3 час.

Я давно хотел вас спросить, как художник художника - вы рисовать умеете?..
Kentarius
    
Посты: 40
Откуда: Flensburg
Возраст:
03-02-2013 14:40 GMT3 час. #1653150   
Всем спасибо!!! выносят с первого выстрела!:)) приходится теперь тарится под каждым кустом!!!
нужно было просто в иммунитете fire_wound_immunity поставить на 2, ну и конечно же вероятность попадания сделать 1.0. чистый хардкор получился:)


antreg
    
Посты: 176
Откуда: vrn
Возраст:
09-02-2013 13:30 GMT3 час. #1653708   
Добрый день.
Требуется помощь для небольшой сюжетной модификации Ф.О.Т.О.Г.Р.А.Ф (основа ТЧ + АМК)
Нужно скриптовой функцией уложить актёра на землю (на пол) и чтобы он некоторое заданное время смотрел в определённую точку, прописанную в аллспавне или задать дирекшн для взгляда.
(в этот момент актёр обездвижен и нет возможности использовать инвентарь,
а соответственно и оружие. Это для справки. С этим нет проблем в реализации.)
Смысл в следующем:
есть интересная стандартная анимация ТЧ для НПС: doctor_wakeup.
Это не вошедшая в оригинал ТЧ анимация, когда доктор склоняется над Меченым
и произносит свой монолог про растяжку и т.д.
Я сделал совсем другой сюжет и столкнулся с необходимостью реализовать
такую скриптовую сценку.
Не хвататет только одного:
как запрограммировать лежание ГГ на уровне земли (пола)?
Можно либо функцией, либо постпроцессом или эффектом из логики рестриктора или НПС, неважно.
Главное, чтобы ГГ смотрел в нужную точку.
Пытался использовать интересный эффект камеры, когда актёр лежит на спине (%=run_cam_effector(prison_0:1003:true)%)
Но в этом случае ГГ смотрит исключительно в потолок.
Нужно направление взгляда перевести на НПС, который говорит монолог.
Актёр должен быть в этот момент на уровне земли (пола),
так как анимка doctor_wakeup - это сильный наклон НПС к лежащему на земле (полу) ГГ.


Ф.О.Т.О.Г.Р.А.Ф : http://fotograf.do.am
SSSaViNNN
    
Посты: 3
Откуда:
Возраст: 25
11-02-2013 13:48 GMT3 час. #1653908   
Люди? кто убил Клыка? Шрам или Волкодав?
оба наёмники
у обоих шрам на лице
у обоих светлые глаза


Trаum
    
Посты: 4221
Откуда: Город бесов
Возраст: 28
11-02-2013 13:59 GMT3 час. #1653910   
SSSaViNNN, сюда иди.


New world today!
SSSaViNNN
    
Посты: 3
Откуда:
Возраст: 25
11-02-2013 14:38 GMT3 час. #1653911   
Спасибо)


ColR_iT
    
Посты: 398
Откуда: Киев
Возраст: 36
12-02-2013 13:14 GMT3 час. #1653995   
А кто сказал, что Клыка убили!?


Те мнения, которые пишутся с ошибками, не воспринимаются как умные…
Лучше иной раз тупить, но умным быть, чем постоянно умничать, но быть тупым.
Все, кто еще говорит «ИХНИЙ», будут гореть в аду!


Форумы Архив » Свалка Вопросы и ответы (старое, по 21.10.13)


Эта тема закрыта, публикация новых сообщений недоступна.
Продолжая пользоваться сайтом, вы соглашаетесь с использованием файлов cookie. Страницы сайта могут содержать информацию, запрещенную для
просмотра посетителям младше 18 лет. Авторское право на серию игр «S.T.A.L.K.E.R» и используемые в ней материалы принадлежит GSC Game World.

Использование материалов сайта возможно с разрешения администрации. Все права защищены. © 2004–2025 «Stalker-Portal.ru»