В последнее время люди постоянно меня спрашивали как создать скрипт гулага для смартеррейнов. Чтобы постоянно не отвечать на каждое отдельное письмо, я решил написать небольшой тутор. Прежде чем начать, хотелось бы предупредить, что не являюсь экспертом в подобного рода вещах и некоторые моменты мне всё 
 еще не ясны до конца, так что вероятно я не смогу объяснить всё правильно. Также я буду использовать ST как абревиатуру смартеррейна. Этот тутор посвящен НПС в ST, но он также сгодится и для мутантов. Предполагаю что вы знакомы с:  
Цитата
- луа программированием 
 - редактированием all.spawn 
 - работа с вейпоинтами(патрульными путями) 
 - утилитами аи
 В первую очередить подумайте о своём ST, где бы его заспавнить, сколько нпс/мутантов будут в нем выполнять определенную "работу", когда ST должен активироваться/отключаться, сколько и какие состояния будет у вашего 
 ST и тд. Думаю, наиболее эффективный способ объяснить вам как это работает на примере. Давайте предположим.. мы хотим поставить ST(smart terrain) на Кордоне для 3х бандитов. 
 1. Спавн ST:  
Код
[2515] 
 ; cse_abstract properties (основные параметры) 
 section_name = smart_terrain 
 name         = esc_bandits_smart_terrain 
 position     = 131.02030944824,0.065616846084595,-248.9094543457 
 direction    = 0,0,0 
     
 ; cse_alife_object properties (параметры объекта) 
 game_vertex_id  = 635 
 distance        = 9.09999942779541 
 level_vertex_id = 363757 
 object_flags    = 0x==3e 
 custom_data     = <<END 
 [smart_terrain] 
 type     = esc_bandits_smart_terrain 
 cond     = {-infoportion} 
 capacity = 3 
 squad    = 1 
 groups   = 5 
 respawn  = esc_respawn_inventory_box_0002 
 END 
     
 ; cse_shape properties (параметры шейпа объекта) 
 shapes        = shape0 
 shape0:type   = sphere 
 shape0:offset = 0,0,0 
 shape0:radius = 20.55957102775574 
     
 ; cse_alife_space_restrictor properties (параметры рестриктора) 
 restrictor_type = 3 
     
 ; se_smart_terrain properties (параметры смарттеррейна)
 Эта наиболее важная часть:  
Код
type     = esc_bandits_smart_terrain 
 cond     = {-infoportion} 
 capacity = 3 
 squad    = 1 
 groups   = 5 
 respawn  = esc_respawn_inventory_box_0002
Цитата
type название вашего нового ST(обязательно) 
 cond описывает условия, которые необходимы для включения гулага(по желанию) 
 capacity количество мутантов/нпс, которое может вместить смарттеррейн(обязательно) 
 squad, groups - номер сквада и количество групп(по желанию) 
 respawn название тайника(синяя коробка) куда будут спавниться предметы, когда мы вызовем респавн в ST.(по желанию)
 2. Спавн нпс/мутантов и назначение(биндинг) их к нашему ST: для этого мы должны добавить каждому мутанту/нпс определенную логику:  
Код
custom_data = <<END 
 [smart_terrains] 
 esc_bandits_smart_terrain = true 
 END
 Если таковых нпс не обнаружится то гулаг выберет себе население из числа заспавнившихся в Зоне нпс с подходящими параметрами. Даже если они на другой локации. 
 3. Добавляем "работу" (логика) для каждого нпс/мутанта из нашего ST(для каждого состояния). Предположии у ST их два: состояние 0 (описывает какие нпс/мутанты "работают" днем) и состояние 1 (ночью). У нас 3 бандита, определяемся: 
 - bandit1: walker (состояние 0) и kamp (состояние 1) 
 - bandit2: guard (состояние 0) и sleeper (состояние 1) 
 - bandit3: walker (состояние 0 и 1 <= он делает тоже и днём, и ночью) 
 У нас есть 3 способа добавить логику (работу) для каждого нпс/мутанта, мы будем использовать наиболее общепринятый способ, добавим логику в фаил config\misc\gulag_escape.ltx. Она должна выглядеть примерно так:  
Код
;-- bandit1 (walker(прогуливающийся) -> состояние 0, днем) 
 [logic@esc_bandits_smart_terrain_bandit1_walker] 
 active = walker@esc_bandits_smart_terrain_bandit1 
     
 [walker@esc_bandits_smart_terrain_bandit1] 
 path_walk         = bandit1_walk 
 danger            = danger_condition@esc_bandits_smart_terrain 
 def_state_moving1 = patrol 
 def_state_moving2 = patrol 
 def_state_moving3 = patrol 
 meet              = no_meet 
     
 ;-- bandit1 (kamp(лагерь) -> состояние 1, ночью) 
 [logic@esc_bandits_smart_terrain_bandit1_kamp] 
 active = kamp@esc_bandits_smart_terrain_bandit1 
     
 [kamp@esc_bandits_smart_terrain_bandit1] 
 center_point = bandit_kamp 
 path_walk    = bandit_kamp_task 
     
 ;-- bandit2 (guard(охранник) -> состояние 0, днем) 
 [logic@esc_bandits_smart_terrain_bandit2_walker] 
 active = walker@esc_bandits_smart_terrain_bandit2 
     
 [walker@esc_bandits_smart_terrain_bandit2] 
 path_walk = bandit2_walk 
 path_look = bandit2_look 
 danger    = danger_condition@esc_bandits_smart_terrain 
     
 ;-- bandit2 (sleeper(спящий) -> состояние 1, ночью) 
 [logic@esc_bandits_smart_terrain_bandit2_sleeper] 
 active = sleeper@esc_bandits_smart_terrain_bandit2 
     
 [sleeper@esc_bandits_smart_terrain_bandit2] 
 path_main = bandit2_sleep 
 wakeable  = false 
     
 ;-- bandit3 (guard -> состояние 0 и 1, днем/ночью) 
 [logic@esc_bandits_smart_terrain_bandit3_walker] 
 active = walker@esc_bandits_smart_terrain_bandit3 
     
 [walker@esc_bandits_smart_terrain_bandit3] 
 path_walk = bandit3_walk 
 path_look = bandit3_look 
     
 [danger_condition@esc_bandits_smart_terrain] 
 ignore_distance_corpse = 0 
 ignore_distance        = 0
 4. Теперь нам нужно заскриптовать наш ST. Так что добавим наш код в файл скрипта \gulag_escape.script. Есть еще несколько моментов, которые мы должны здесь доделать (каждый из этих шагов обязателен): 
 - грузим логику (работу) для каждого нпс/мутанта и для каждого состояния -> 
Код
function load_job(...) 
     
 if type == "esc_bandits_smart_terrain" then 
   t = {} 
   ;-- "соеденительная секция" для логики, определяем ltx фаилом 
   t.section = "logic@esc_bandits_smart_terrain_bandit1_walker" 
   ;-- no idea, probably describes after what time 
   ;-- npc will use this job again (?) 
   t.idle = 0 
   ;-- no idea but i guess it's optional 
   t.timeout = 0 
   ;-- пріоритет 
   t.prior = 100 
   ;-- нпс будет использовать эту логику,   
          ;-- если ST переключится в это состояние 
   ;-- в этом случае - состояние 0 (день) 
   t.state = {0} 
   ;-- Какой squad и group назначится персонажу принявшему эту работу. 
   t.squad = squad 
   t.group = groups[1] 
   ;-- no idea what means position_threshold 
   t.position_threshold = 100 
   ;-- описывает нпс в этом состоянии: онлайн или офлайн 
   ;-- онлайн = истина по дефолту 
   t.online = true 
   ;-- описывает рестрикторы (куда нпс могут/не могут пойти) 
   t.in_rest = "" 
   t.out_rest = "" 
          ;-- ввиду особого способа присвоения работ в    
          ;-- smart_terrain.script вы никогда не знаете, какая работа 
   ;-- будет использоваться каждым нпсом; если вы хотите быть уверенным 
   ;-- что конкретный нпс взял конкретную работу, тогда 
   ;-- вам нужно заюзать предикатную функцию; в этом слуае 
   ;-- мы хотим чтобы эта работа присвоилась мастеру бандиту 
   t.predicate = function(obj_info) return obj_info.rank >= 900 end 
   table.insert(sj, t) 
     
   t = {section = "logic@esc_bandits_smart_terrain_bandit1_kamp", 
   idle = 0, timeout = 0, prior = 100, state = {1},squad = squad, 
   group = groups[1], position_threshold = 100, online = true, in_rest = "", 
   out_rest = "", predicate = function(obj_info) return obj_info.rank >= 900 end} 
   table.insert(sj, t) 
     
   ;-- bandit2 -> состояние 0 (день) 
   t = {section = "logic@esc_bandits_smart_terrain_bandit2_walker", 
   idle = 0, prior = 5, state = {0}, squad = squad, group = groups[1], 
   in_rest = "", out_rest = ""} 
   table.insert(sj, t) 
     
   ;-- bandit2 -> состояние 1 (ночь) 
   t = {section = "logic@esc_bandits_smart_terrain_bandit2_sleeper", 
   idle = 0, prior = 5, state = {1}, squad = squad, group = groups[1], 
   in_rest = "", out_rest = ""} 
   table.insert(sj, t) 
     
   ;-- bandit3 -> состояние 0 (день) и состояние 1 (ночь) 
   t = {section = "logic@esc_bandits_smart_terrain_bandit3_walker", 
   idle = 0, prior = 5, state = {0, 1}, squad = squad, group = groups[1], 
   in_rest = "", out_rest = ""} 
   table.insert(sj, t) 
 end
 Еще один момент о состояниях ST, всё зависит от того сколько у вас их в ST. Еще одна важной вещью является добавление логики для каждого состояния. Например в вашем ST такие состояния:  
Цитата
0 - нпс оффлайн 
 1 - нпс онлайн (день) 
 2 - нпс онлайн (ночь) 
 3 - нпс онлайн, они решили напасть на другой ST 
 4 - нпс онлайн, ГГ напал на них
 К сведению, меня не прет заполнять такое большое количество таблиц, так что обычно я использую эту функцию:  
Код
function fill_tbl(section, idle, prior, states, squad, group, in_rest, out_rest, online, gulag_name) 
   local tbl = {} 
     
   tbl.section = "logic@" .. gulag_name .. "_" .. section 
   tbl.idle = idle 
   tbl.prior = prior   
   tbl.state = {} 
     
   for index = 1, #states do 
    table.insert(tbl.state, states[index]) 
   end 
     
   tbl.squad = squad 
   tbl.group = group 
   tbl.in_rest = in_rest 
   tbl.out_rest = out_rest 
   tbl.online = online 
   return tbl 
 end
 Используя функцию выше, мы можем загружать логику наподобие этой:  
Код
if type == "esc_bandits_smart_terrain" then 
   local t = table.insert(sj, fill_tbl("bandit1_walker", 0, 100, {0}, squad, groups[1], "", "", true, type)) 
   t.timeout = 0 
   t.position_threshold = 100 
   t.predicate = function(obj_info) return obj_info.rank >= 900 end 
   table.insert(sj, t) 
     
     
   t = table.insert(sj, fill_tbl("bandit1_kamp", 0, 100, {1}, squad, groups[1], "", "", true, type)) 
   t.timeout = 0 
   t.position_threshold = 100 
   t.predicate = function(obj_info) return obj_info.rank >= 900 end 
   table.insert(sj, t) 
     
   table.insert(sj, fill_tbl("bandit2_walker", 0, 5, {0}, squad, groups[1], "", "", true, type)) 
   table.insert(sj, fill_tbl("bandit2_sleeper", 0, 5, {1}, squad, groups[1], "", "", true, type)) 
   table.insert(sj, fill_tbl("bandit3_walker", 0, 5, {0, 1}, squad, groups[1], "", "", true, type)) 
 end 
     
 - автоматически изменяем работу для каждого нпс/мутанта -> function load_states(...) 
     
 if type == "esc_bandits_smart_terrain" then 
   return function(gulag) 
    if not db.actor then 
     return gulag.state 
    end 
    if level.get_time_hours() >= 5 and level.get_time_hours() <= 22 then 
            return 0  -- переключает всех мутантов/нпс на дневную работу 
    else 
     return 1  -- ереключает всех мутантов/нпс на ночную работу 
    end 
   end 
 end 
     
 - убедитесь что наш ST будет использоваться только для бандитов -> function checkStalker(...) 
     
 if gulag_type == "esc_bandits_smart_terrain" then 
   return npc_community == "bandit" 
 end
 Так же существуют универсальные гулаги General_lager для сталкеров. Они считаются упрощенными гулагами. Пример, создаем смарт:  
Код
[9999] 
 ; cse_abstract properties (основные параметры) 
 section_name = smart_terrain 
 name         = esc_gen_lager 
 position     = 131.02030944824,0.065616846084595,-248.9094543457 
 direction    = 0,0,0 
     
 ; cse_alife_object properties (параметры объекта) 
 game_vertex_id  = 635 
 distance        = 9.09999942779541 
 level_vertex_id = 363757 
 object_flags    = 0x==3e 
 custom_data     = <<END 
 [smart_terrain] 
 type     = general_lager 
 capacity = 3 ;вместимость 
 communities = bandit ; комьюнити населения 
 END 
     
 ; cse_shape properties (параметры шейпа объекта) 
 shapes        = shape0 
 shape0:type   = sphere 
 shape0:offset = 0,0,0 
 shape0:radius = 20.55957102775574 
     
 ; cse_alife_space_restrictor properties (параметры рестриктора) 
 restrictor_type = 3 
     
 ; se_smart_terrain properties (параметры смарттеррейна)
 General_lager автоматически соберет все точки путей на уровне начинающиеся на имя смарта(в нашем случае esc_gen_lager) и разделит их названия таким образом: (имя_смарта)_(аи схема)_(номер если требуется,напрмер если 2 walkerа то 1 и 2 соответственно)_(поднастройка схемы)_(состояние гулага 1 или 0,день или ночь) пример: esc_gen_lager _walker _1 _walk _1 (walk то же что и path_walk,look это path_look соответственно) 
 Пришедший на general_lager сталкер рандомно примет любую свободную работу работой считается комбинация схем с одним номером. например esc_gen_lager_walker_1_walk_1 и esc_gen_lager_walker_1_look_1 это схема дневной работы одного персонажа из гулага. 
 Так что для каждого general_lager нужны заранее расставленые точки путей для него. 
 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 
 Создание Смарт террэйна на основе схемы General Lager 
 Итак, вы хотите создать смарт, но не охота копошится в скриптах и конфигах и создавать свои скрипты для смарта? тогда этот способ именно для вас. Генерал лагер это универсальный смарт, с его помощью можно заселить локации или переобустроить ПЫСовские. Начнем с простенького. 
 Создадим смарт для мутантов. 
 Открываем сдк, жмем spawn element>ai>smart terrains, шлепаем сие на локацию, затем переходим в shape>sphere(можно и box по желанию) и снова вставляем сие на локацию, увеличиваем до нужных размеров (не сильно больших), переходим обратно в режим spawn element, жмем кнопку attach object и кликаем на созданной нами сфере. Мы создали смарт с зоной влияния. открываем properties правым щелчком мыши или eneter по умолчанию. открываем custom data и пишем в ней [smart_terrain] type = general_lair capacity = 4 где capacity = 4, это число мутантов, которые могут в ходить в смарт (тобешь есле capacity = 4, то в смарте будет 4 места для мутанта) переходим в режим way points, добавляем новый путь (он будет состоять из одной точки) и обзываем его smart_name_home_1, где smart_name это имя вашего смарта, все, смарт готов, осталось только создать самих мутантов, берем любого, нужного вам мутанта, ставим в зону влияния смарта и идем в custom data, в ней пишем [smart_terrain] smart_terrain_name = true где smart_terrain_name - имя вашего смарта. Все, смарт террэйн для мутантов готов, собираем уровень и идем туда, куда поставили свой смарт и любуемся тем, что мутанты не разбредаются кто куда, а чем то занимаются рядом со смартом 
 Примечание. 
 Если вы создали смарт на своем, новом, уровне то нужно добавить в config\misc\general_lair  
Код
[Имя уровня] boar = weak, normal, strong bloodsucker = weak, normal, strong flesh = weak, normal, strong dog = weak, normal, strong pseudodog = weak, normal, strong giant = weak, normal, strong zombie = weak, normal, strong burer = weak, normal, strong controller = weak, normal, strong poltergeist = weak, normal, strong snork = weak, normal, strong tushkano = weak, normal, strong
 и в тои же папке в smart_terrain_presets добавить  
Код
[Имя уровня] stalker = novice, experienced, veteran, master monolith = novice, experienced, veteran, master military = novice, experienced, veteran, master killer = novice, experienced, veteran, master ecolog = novice, experienced, veteran, master dolg = novice, experienced, veteran, master freedom = novice, experienced, veteran, master bandit = novice, experienced, veteran, master zombied = novice, experienced, veteran, master 
 boar = weak, normal, strong bloodsucker = weak, normal, strong flesh = weak, normal, strong dog = weak, normal, strong pseudodog = weak, normal, strong giant = weak, normal, strong zombie = weak, normal, strong burer = weak, normal, strong controller = weak, normal, strong poltergeist = weak, normal, strong snork = weak, normal, strong tushkano = weak, normal, strong
 Создадим смарт для НПС 
 И так, повторяем действия сделанные выше Открываем сдк, жмем spawn element>ai>smart terrains, шлепаем сие на локацию, затем переходим в shape>sphere(можно и box по желанию) и снова вставляем сие на локацию, увеличиваем до нужных размеров (не сильно больших), переходим обратно в режим spawn element, жмем кнопку attach object и кликаем на созданной нами сфере. открываем properties правым щелчком мыши или eneter по умолчанию. открываем custom data и пишем в ней [smart_terrain] type = general_lager capacity = 5 что такое capacity вы уже знаете. Создаем пути для НПС (Работы для НПС) вот примеры путей  
Код
    * smart_name_kamp_1 
      * smart_name_sleep_1 
      * smart_name_walker_1_walk \ smart_name_walker_1_look 
      * smart_name_walker2_1_walk \ smart_name_walker2_1_look 
      * smart_name_patrol_1_walk 
      * smart_name_guard_1_walk \ smart_name_guard_1_look 
      * smart_name_sniper_1_walk \ smart_name_sniper_1_look 
 Соответсвенно слева путь НПС, а справа направление его взгляда. smart_name - имя вашего смарта (его нужно вставлять перед любым названием пути, так же необходимо писать номер пути между видом пути и walk\look) теперь по подробнее о видах путей.  
Цитата
 * kamp - Это лагерь сталкеров у костра. Вокруг этой точки они будут рассказывать анекдоты, есть колбасу\хлеб, пить водку. 
 * sleep - место для сна НПС состоит из двух точек, НПС ложится на нулевой точке и смотрит в первую. 
 * walker - обычное бродяжничество по точкам НПС, при использовании точек для пути больше двух - smart_name_walker_1_look не применяется (путь у этого вида волкера должен быть не замкнут и состоять из точек пути больше одного) 
 * walker2 - тот же волкер что и выше, только он ходит по замкнутым путям, лук пути почти не используются. 
 * patrol - патруль лагеря, используется во множественном количестве (количество точек пути в одном пути больше единицы, путь должен быть замкнут),не применяются look пути 
 * guard - часовой, используется в двойном количестве (в пути имеется две точки), очень часто используется look пути 
 * sniper - работа для снайпера, задается двумя точками и look путями. Почему то НПС игнорируют данную работу. 
 Так, теперь, когда вы узнали виды работ - создайте по вкусу работы (их количество не должно превышать количество сталкеров в смарте) и не забудьте приписывать в начале имя смарта (например red_bridge_blokpoats_kamp_1) все, собираем уровень и смотрим на наш смарт, есле вы создали несколько лагерей на одном уровне с одинаковой кастом датой и ваши НПС начали разбредатся - сначала проследите, куда они пойдут, может их принял под себя другой смарт (лично у меня такое было) 
 smart_name_kamp_1 имя_гулага_kamp_коментарии типа [esc2_tunnel3_home_1] причем вместо 1 может быть все что угодно 
 esc2_tunnel3 название смарта 
 home используемая схема поведения 
 _1 коментарии 
 да и незабутьте файл 
 gulag_general.script именно в нем указанно все что касается гулагов этого типа