Это популярное сообщение. Rolan 22 Опубликовано 28 Декабря 2010 Это популярное сообщение. Поделиться Опубликовано 28 Декабря 2010 Software Development Kit для движка X-Ray 1.6 (версия S.T.A.L.K.E.R.: Зов Припяти) Полная версия, позволяет работать с модификациями любой сложности, вплоть до тотальных конверсий с полностью новым содержимым. Инструментарий предоставляется "как есть" (as is), при этом компания GSC Game World не предоставляет какой-либо технической поддержки по данному SDK. Ниже приведены основные изменения по сравнению с предыдущими версиями SDK. В отличие от SDK 0.5 (ЧН), предназначенного исключительно для работы с мультиплеерными уровнями и содержавшего лишь LevelEditor с основными компиляторами, SDK 0.7 содержит полный набор инструментов последних версий: -- ActorEditor -- LevelEditor -- ParticleEditor -- ShaderEditor -- Postprocess -- DialogEditor -- ScriptDebugger А также компиляторов: -- xrAI -- xrDO -- xrLC (+ coordinator + agent) ---В компиляторах новой версии улучшена поддержка многопоточной работы на многоядерных процессорах, и они используют до 4гб памяти (для сравнения: компиляторы ЧН хоть и поддерживали 4 ядра, но в них еще не была реализована адресация памяти, а в ТЧ и вовсе использовался только один поток). Скорость компиляции при полной нагрузке, соответственно, может вырасти до двух раз по сравнению с ЧН. ---Также стоит заметить, что именно невозможность адресации компилятором более, чем 2гб RAM, была причиной ряда ограничений, с которыми сталкивались разработчики модов: на максимальный размер ai-сетки (и, следовательно, размер играбельной площади уровня) и на максимальное количество вершин, - причем в ситуациях, когда сама игра бы вполне выдержала уровень. Разумеется, это не означает, что стоит пробовать делать уровни в 5х5км или 20 миллионов полигонов, но ситуаций, когда движок может работать с уровнем, а компилятор - не в состоянии его собрать из-за ошибок переполнения памяти, - происходить уже не должно. --- Нельзя не упомянуть о реализации для всех редакторов SDK поддержки Windows Vista и Windows 7. ---Важное нововведение - возможность компиляции уровня на нескольких компьютерах одновременно. Выполняется она с помощью xrLC и дополнительных приложений. Один компьютер выполняет роль "координатора", остальные, "агенты", работают с определенными им задачами. Для простоты работы к SDK приложены уже настроенные исполняемые файлы, с которыми достаточно лишь указать имя уровня и IP координирующего компьютера. Смысл использования такой компиляции понятен - она позволяет собирать сложные уровни с очень высокими установками качества за куда меньшее время, чем на одном пк. Разумеется, со времен xrLC ТЧ, у которого уходило до недели чистого времени на сборку крупного уровня в высоком качестве, скорость работы компилятора возросла до четырех раз, но время компиляции всё равно не назовешь быстрым. --- Совершенно кардинальных изменений нет - движок создан не вчера, и большинство инструментов подходит для работы в неизменном виде уже который год. Главным является то, что все инструменты присутствуют в полном объеме, и совместимы с последними версиями форматов, используемых в X-Ray 1.6 (ЗП). --- Отличия, о которых стоит упомянуть отдельно, могут быть приведены как по сравнению с SDK 0.5 (ЧН), так и с SDK 0.4 (ТЧ), так как в SDK ЧН целый ряд инструментов отсутствовал. --- Доработан инструмент Move: теперь необязательно переключаться нужную ось для перемещения объекта: на объекте отображаются контроллеры, за которые достаточно просто потянуть курсором. --- Появилась отсутствовавшая в SDK ЧН возможность использования spawn element классов: ---- actor ---- camp ---- smart_terrain ---- smart_cover ---- и им подобных Таким образом, в SDK появилась возможность работы со смарткаверами (которые хоть и появились впервые в ЧН, но в его SDK были недоступны) в частности и уровнями для одиночной игры в целом (имевшаяся в LE ЧН, но достаточно ограниченная). --- Убран ряд устаревших классов spawn element, добавлены задействованные в ЗП классы. --- Появился инструмент Simulate / UseSimulatePositions, предназначенный для проверки физики прямо в редакторе. --- Для ряда классов spawn element отображаются вспомогательные модели, упрощающие работу в ситуациях, когда в сцене много объектов. Приложение для создания и редактирования файлов .ppe (постпроцесс-эффектов). Достаточно просто в освоении: семь классов эффектов, ряд параметров в каждом, возможность строить последовательности и другие возможности. Приложение для редактирования диалогов игры в формате .xml с поддержкой условий и проверок has_info, dont_has_info, give_info, disable_info, precondition, action. Отладка Lua скриптов, проверка синтаксиса и их валидности, поддерживает работу с Source Control Center. --- Формат уровней (за исключением данных, относящихся к xrAI), практически не менялся, поэтому результаты работы xrLC могут быть использованы и в ЧН. Разумеется, это относится только к мультиплеерным картам либо использованию геометрии. Таким образом, если вы хотите использовать SDK 0.7 для компиляции одиночного уровня к ЧН (скажем, из-за скорости работы xrLC), то это возможно, - но, соответственно, только с xrAI от ЧН. ---Файлы, собранные xrDO, совместимы как с ЗП, так и с ЧН и ТЧ. Файлы .thm совместимы со всеми версиями игры вплоть до ТЧ 1.0004. Формат скелетных объектов .ogf в ЗП и ЧН одинаков, - результаты работы в ActorEditor можно использовать в обеих играх. --- Благодарим всех поклонников S.T.A.L.K.E.R.-a за интерес к нашей игре. --- Особая благодарность модмейкерам и @bac9-flcl за помощь в сборке этого SDK. Причины вылета Invalid vertex for object: 1. В секции этого объекта position или level_vertex_ud НЕ соответствуют game_vertex_id. Решение простое - загрузите локацию и замерьте нормальные координаты. 2. В секции этого объекта неправильный object_flags. Берите его от объекта такого же типа. Для компиляции карты (в xrLC) с нормальным освещением используйте ключ -nosmg xrLC.exe -nosmg -f test_map X-Ray SDK v.0.7 (размер файла: 446 мб) Зеркало (спасибо @stunder) Патч 1.0 (размер файла: 3,82 мб) Документация к SDK Плагин импорта статики формата object в 3ds Max (плагин кривоватый, автор Neo][) Плагин импорта статики формата geom в 3ds Max (surfer, Neo][): Плагины импорта/экспорта геометрии в Milkshape 3D (bardak, Kamikazze): Плагины импорта/экспорта геометрии в Maya (bardak, surfer): Плагины экспорта геометрии из 3ds Max/Maya/Lightwave (официальные от GSC): Ускоренные компиляторы для ЧН-ЗП, присутствует обход ошибки Invalid Face (@macron, drvoodoo-guru) Конвертер уровней в формате СДК ТЧ в формат СДК ЧН и ЗП (S_P_S), зеркало (спасибо @genior) Декомпилятор уровней, конвертер моделей и анимаций и пр. (bardak, x-ray engine toolset team) Конвертер файлов thm из формата ТЧ в формат ЧН/ЗП (Kln) Конвертер scene_object.part любой карты из SDK ТЧ в формат SDK ЧН/ЗП Перед тем, как задать вопрос, пожалуйста, прочитайте вот это и это. Поверьте, там есть ответы на многие ваши вопросы. Также используйте поиск по форуму. Bопросы, на которые уже были ответы, будут нещадно удаляться. Если пишете сообщение об ошибке или вылете, то обязательно прикладывайте лог: без него весь смысл вашего сообщения теряется и оно, скорее всего, будет удалено. 3 4 Ссылка на комментарий
Wo1fRam 79 Опубликовано 28 Апреля 2013 Поделиться Опубликовано 28 Апреля 2013 "Молоко" будет всегда, если на драфте компилить. На максе если компилить, то надо будет маску террейна делать, а то на динамике тоже будет "молоко". Суффикс _S скорее всего означает "shape". Не думаю, что это сильно важно. Мой канал на YouTube Бессмысленно осмысливать смысл неосмысленными мыслями. Ссылка на комментарий
genior 45 Опубликовано 28 Апреля 2013 Поделиться Опубликовано 28 Апреля 2013 ......с добавлением "_S" У терейна локации в состав входят несколько элементов - трава, земля, асфальт, песок и т.п. К каждому элементу присваевается одна и та же текстура терейна, так вот - во многих случиях при экспорте в СДК остаётся одна текстура у терейна, остальные "сливаются" в неё так как у элементов имя текстуры одинакокое. В таком случае мы не сможем в СДК каждому элементу присвоить свой шейдер так как у нас осталась одна присвоенная текстура. Для этого и применяют разные имена материалов чтоб не потерять разграничение элементов в едином терейне. Не обязательно писать приставку "_S" , можно просто каждому элементу дать своё имя: grass, grunt, asfalt, sand и т.д. Ссылка на комментарий
Jeka81 75 Опубликовано 28 Апреля 2013 Поделиться Опубликовано 28 Апреля 2013 (изменено) О! Алилуйя! Скомпилированный на максимуме уровень запустился!!! Скопировал ВСЕ текстуры папки terrain с gamedat'ы из SDK в папку с игрой. НО... текстур в игре так и не появилось, более того - вода стала черной. Ну - хоть какое-то продвижение. Обязательна ли маска если на уровне у меня нет травы? Я маску не применял. Второй вопрос: Какое значение должно быть у параметра Base в ImageEditor когда я импортирую в SDK текстуру терреина? Я выставил так: Type - Terrain Alpha - present Format - DXT1 Base - Blin <-> Phong (еще есть OrenNayar <-> Blin, Phong <-> Metal, Metal <-> OrenNayar - какой ставить? Хотя последние два на вряд ли) Так же есть вкладка Details, в котрой есть параметр Texture в котором у меня ничего не присвоено. Может что в настройках здесь напутал? Изменено 28 Апреля 2013 пользователем Jeka81 С#Н#Т#Р# (CoP 1.6.02) Ссылка на комментарий
Сталкер Лом 356 Опубликовано 1 Мая 2013 Поделиться Опубликовано 1 Мая 2013 Здравствуйте. Проблема с Аивраппером: при запуске батника с содержимым aiwrapper -draft -f agroprom pause идёт запуск xrAI, затем, мгновенно, происходит вылет. Вот информация из ЛОГа: log started (console and aiwrapper.log)loading aiwrapper.iniupdating $2215_game_levels$\agroprom\build.aimapupdating $2215_game_levels$\agroprom\build.cformupdating $2215_game_levels$\agroprom\build.prjlaunching 'xrAI.exe -draft -f agroprom'updating $game_levels$\agroprom\level.ai Что ему не нравится? P.S. Сборка локации происходила на СДК ЗП и скомпилирована на драфте. Работы на Artstation - https://www.artstation.com/artist/stalker_lom Ссылка на комментарий
Страховид 16 Опубликовано 1 Мая 2013 Поделиться Опубликовано 1 Мая 2013 А при чём тут аивраппер? О_о. Или я чего-то не понимаю? Это же не относится к СоР, он же для Теней. Порядок запуска батников из папки \X-Ray CoP SDK\editors: tool_compile_xrLC_all, tool_compile_xrAI_draft, tool_create_spawn. Вместо <%1> название локации. 1 Обещаю, что никого в ответ минусить не стану) Чмоки))) Ссылка на комментарий
Jeka81 75 Опубликовано 4 Мая 2013 Поделиться Опубликовано 4 Мая 2013 Третью неделю бьюсь об одно и то-же - не могу запустить свою локацию (ровная плоскость 50*50 м). Уже в 3d max'e сделал новую - экспортировал в object. Все прошло успешно, в LevelEditor сцена создана, актер поставлен, граф-поинты расставлены (2 шт), свет, дефолтный сектор. Если раньше компиляция на максимуме проходила нормально, но сама игра не запускалась, то на этот раз уже сам компилятор вылетает с таким логом: FATAL ERROR: Expression : assertion failed Function : CBuild::PreOptimize File : D:\prog_repository\sources\trunk\utils\xrLC\xrPreOptimize.cpp Line : 79 Description : ix<=HDIM_X && iy<=HDIM_Y && iz<=HDIM_Z Что это значит? С#Н#Т#Р# (CoP 1.6.02) Ссылка на комментарий
stalker_bes 0 Опубликовано 5 Мая 2013 Поделиться Опубликовано 5 Мая 2013 Если у тебя просто ровная плоскость то ошибка скорее всего из-за этого. Попробуй изменить немного геометрию. Ссылка на комментарий
Сталкер Лом 356 Опубликовано 7 Мая 2013 Поделиться Опубликовано 7 Мая 2013 Здравствуйте, снова с вопросами к вам... Собрал таки локацию в первый раз - красота, хоть и на драфте, но пришла в голову мысль облагородить статичные модели (я над Агропромом колдую: вот помните в ТЧ у НИИ вертолет? Я решил сделать так, чтобы можно было залазить в "пассажирский вагон" и по аналогии так ещё с некоторыми моделями) так меня насторожило то, что СДК отказывается делать для этих моделей ЛОДы (а модели будут по полигональности несколько богаче нежели "старые" модели), ну, покумекал и решил снова собирать так как есть. И получилось, возле НИИ вертолет как ему и положено лежит, однако в озерце над водою застыли в позах неудачливых водителей "буханки" пара трупов вояк... Собственно, новая модель "Жигули" тоже исчезла. Из за чего СДК "съел" модели? Подозрения у меня есть: Вот этот кусочек меня насторожил, может это из за этого, однако же "Жигули" делалась на основе модели от GSC и полигонаж у неё меньше (двери, капот и сиденья отсутствуют)... ...* New phase started: Merging geometry...| Processing...| | ! ERROR: subdiv #98318 has more than 4096 faces (6739)| | 2254 subdivisions.| | ! ERROR: subdiv #2253 has more than 4096 faces (6739) И ещё вопрос такого плана: я уже давно подключил Кордон из ТЧ, но сейчас более-менее научился работать с СДК и хочу: а) заменить террейн на версию ЧН и "посадить на этот террейн несколько новых объектов и просчитать АИ-сетку. б) в некоторых местах сделать мелкую корректировку геометрии (сделать дырку в колючей проволоке, укрепить блок-пост и т.п.) и соответственно переделать АИ-сетку. В каком случае после компиляции Кордон будет играбелен без переделки all.spawn (ибо у меня там множества точек путей квестовым NPC налажено, много будет переделывать в плане пересчёта level_vertex ) и вообще, будет ли он играбелен? Ну, и последний вопрос: как высчитываются level_vertex и game_vertex ? По Террейну? Заранее спасибо. Работы на Artstation - https://www.artstation.com/artist/stalker_lom Ссылка на комментарий
dmitry-strelok 0 Опубликовано 9 Мая 2013 Поделиться Опубликовано 9 Мая 2013 Здравствуйте,тут такой вопрос. Я сделал симмуляционный сквад.Появился вылет. Expression : !m_error_code Function : raii_guard::~raii_guardFile : D:\prog_repository\sources\trunk\xrServerEntities\script_storage.cppLine : 748Description : ... - Зов Припяти\gamedata\scripts\smart_terrain.script:1256: attempt to compare nil with number Вообще со сквадами у меня все хорошо,единственная проблема в симмуляционных сквадах.Уже как месяц пытаюсь разобраться.Вот и пришел к вам. Вот что я делал. simulation прописал вот что: esc_stalker_base_default3_squad = esc_stalker_baseesc_stalker_base_default4_squad = esc_stalker_base [esc_stalker_base]:default_base - база с которой 2 дефолтовых сквада должны идти.sim_avail = true[esc_stalker_base_default3_squad]:default_squad - 1-й дефолтовый сквад.sim_avail = true[esc_stalker_base_default4_squad]:default_squad - 2-й дефолтовый сквад.sim_avail = true[esc_lost_stoyanka]:default_resource - это свободный смарт,туда кто нибудь из сквадов должен идти.sim_avail = true[esc_lost_stoyanka2]:default_resource - это тоже свободный смарт и тоже кто нибудь из сквадов должен идти.sim_avail = true [esc_stalker_base_default3_squad]:online_offline_groupfaction = stalkernpc = sim_default_stalker_1, sim_default_stalker_0, sim_default_stalker_0, sim_default_stalker_0;spawn_point = esc_stalker_base_mini_bar_spawn_pointstory_id = esc_stalker_base_default3_squad[esc_stalker_base_default4_squad]:online_offline_groupfaction = stalkernpc = sim_default_stalker_1, sim_default_stalker_1, sim_default_stalker_0, sim_default_stalker_0;spawn_point = esc_stalker_base_mini_bar_spawn_pointstory_id = esc_stalker_base_default4_squadТут в принципе 2 дефолтовых сквада. [esc_stalker_base]255,255,255,144[esc_lost_stoyanka]255,255,255,145[esc_lost_stoyanka2]255,255,255,146 Вот esc_lost_stoyanka: [smart_terrain];esc_lost_stoyanka squad_id = 4 max_population = 1Вот esc_lost_stoyanka2:[smart_terrain];esc_lost_stoyanka2 squad_id = 5 max_population = 1 Вроде все.Что может быть не так? Ссылка на комментарий
Shredder 49 Опубликовано 9 Мая 2013 Поделиться Опубликовано 9 Мая 2013 Ты не указал max_population для esc_stalker_base Ссылка на комментарий
dmitry-strelok 0 Опубликовано 9 Мая 2013 Поделиться Опубликовано 9 Мая 2013 Он есть просто я его тут не указал.Там эксклюзивные и т.д. Ссылка на комментарий
Shredder 49 Опубликовано 9 Мая 2013 Поделиться Опубликовано 9 Мая 2013 Ну если и т.д., тогда сам и разбирайся Ссылка на комментарий
dmitry-strelok 0 Опубликовано 9 Мая 2013 Поделиться Опубликовано 9 Мая 2013 (изменено) А нафиг мне разбираться если там все нормально!!!!Но специально для тебя вот: [smart_terrain];esc_stalker_base squad_id = 3 max_population = 10 [exclusive] !Скрыто! Изменено 9 Мая 2013 пользователем dmitry-strelok Ссылка на комментарий
Shredder 49 Опубликовано 9 Мая 2013 Поделиться Опубликовано 9 Мая 2013 У тебя smart_terrain.script отличается от оригинального, потому что на 1256 строке нет операторов сравнения, о чем говорится в логе. Поэтому опять можно только гадать, чего там исправлялось или дописывалось. Покажи хотябы эту строку, а лучше конечно весь файл Ссылка на комментарий
stalker_bes 0 Опубликовано 10 Мая 2013 Поделиться Опубликовано 10 Мая 2013 @dmitry-strelok, Посмотри в SDK правильно ли установил параметры в smart_terrain, проверь вписан твой левел в smart_terrain.script и в sim_board.script Ссылка на комментарий
dmitry-strelok 0 Опубликовано 10 Мая 2013 Поделиться Опубликовано 10 Мая 2013 (изменено) Я заново по правил скрипты и все равно результат тот же.Может статья какая нибудь не полная.Параметры такие. В restrictor type стоит NOT A restrictor. Имя все норм. Хз почему вылет. Могу скрипты скинуть 2. Надо? Вот скрипты. --'****************************************************** --'* Реестр смарт-террейнов. Игровое поле симуляции.--'******************************************************--' В этом ltx хранятся дескрипторы сквадов.squad_ltx = system_ini()setting_ini = ini_file("misc\\simulation.ltx")local group_id_by_levels = {zaton = 1,pripyat = 2,jupiter = 3,labx8 = 4,jupiter_underground = 5,escape = 6}local board = nilsimulation_activities = {stalker = {squad = nil,smart = { base = { prec = function(squad, target) return in_time_interval(18,8) and not xr_conditions.surge_started() and not travel_manager.check_squad_for_enemies(squad) and (target:name() == "zat_stalker_base_smart" or target:name() == "jup_a6" or target:name() == "pri_a16") end },surge = { prec = function() return xr_conditions.surge_started() end },territory= { prec = function() return in_time_interval(8,18) and not xr_conditions.surge_started() end },resource = { prec = function(squad, target) return in_time_interval(8,18) and not xr_conditions.surge_started() end } -- and squad:has_detector()},actor = nil},bandit = {squad = { stalker = { prec = function(squad, target) return in_time_interval(8,21) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end }},smart = { base = { prec = function(squad, target) return in_time_interval(21,8) and not xr_conditions.surge_started() and not travel_manager.check_squad_for_enemies(squad) and (target:name() == "zat_stalker_base_smart" or target:name() == "jup_a10_smart_terrain") end },territory= { prec = function() return in_time_interval(8,21) and not xr_conditions.surge_started() end },surge = { prec = function() return xr_conditions.surge_started() end }},actor = { prec = function(squad, target) return has_alife_info("sim_bandit_attack_harder") and simulation_objects.sim_dist_to(squad, target) <= 150 end }},dolg = {squad = { freedom = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },monster_predatory_day = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },monster_predatory_night = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },monster_vegetarian = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },monster_zombied_day = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },monster_special = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end }},smart = { base = { prec = function(squad, target) return in_time_interval(19,8) and not xr_conditions.surge_started() and not travel_manager.check_squad_for_enemies(squad) and (target:name() == "zat_stalker_base_smart" or target:name() == "jup_a6" or target:name() == "pri_a16") end },territory= { prec = function() return in_time_interval(8,19) and not xr_conditions.surge_started() end },surge = { prec = function() return xr_conditions.surge_started() end }},actor = nil},freedom = {squad = { dolg = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end }},smart = { base = { prec = function(squad, target) return in_time_interval(19,8) and not xr_conditions.surge_started() and not travel_manager.check_squad_for_enemies(squad) and (target:name() == "zat_stalker_base_smart" or target:name() == "jup_a6" or target:name() == "pri_a16") end },territory= { prec = function() return in_time_interval(8,19) and not xr_conditions.surge_started() end },surge = { prec = function() return xr_conditions.surge_started() end }},actor = nil},killer = {squad = nil,smart = { territory= { prec = function() return not xr_conditions.surge_started() end },surge = { prec = function() return xr_conditions.surge_started() end }},actor = { prec = function(squad, target) return simulation_objects.sim_dist_to(squad, target) <= 150 end }},zombied = {squad = nil,smart = { territory= { prec = function() return true end },lair = { prec = function() return true end}},actor = nil},monster_predatory_day = {squad = { monster_vegetarian = { prec = function() return in_time_interval(6,19) end },stalker = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },bandit = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },dolg = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },freedom = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },killer = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }},smart = { territory= { prec = function() return in_time_interval(6, 19) end },lair = { prec = function() return in_time_interval(19,6) end }},actor = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }},monster_predatory_night = {squad = { monster_vegetarian = { prec = function() return in_time_interval(21,6) end },stalker = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },bandit = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },dolg = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },freedom = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },killer = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end }},smart = { territory= { prec = function() return in_time_interval(19,6) end },lair = { prec = function() return in_time_interval(6,19) end }},actor = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end }},monster_vegetarian = {squad = nil,smart = {lair = { prec = function() return true end }},actor = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }},monster_zombied_day = {squad = { stalker = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },bandit = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },dolg = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },freedom = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },killer = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }},smart = { territory= { prec = function() return not xr_conditions.surge_started() end },lair = { prec = function() return in_time_interval(19,6) end }},actor = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }},monster_zombied_night = {squad = { stalker = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },bandit = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },dolg = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },freedom = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },killer = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end }},smart = { territory= { prec = function() return in_time_interval(19,6) end },lair = { prec = function() return in_time_interval(6,19) end }},actor = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end }},monster_special = {squad = nil,smart = { lair = { prec = function() return true end }},actor = nil},}class "sim_board"function sim_board:__init()--' Таблица содержащая смарты и данные о них в формате:--' smart = {smrt, targets = {}, dangers = {}, squads = {}, stayed_squad_quan = 0}self.smarts = {}self.simulation_started = true--' Таблица смартов по именам.self.smarts_by_names = {}--' Таблица существующих отрядов.self.squads = {}--' отрисовывается ли сейчас поле на карте.--self.show_flag = false--' Таблица спаунсмартов. Смарт = уровень.self.spawn_smarts = {}-- Таблица для логовов мутантов на уровняхself.mutant_lair = {}-- Временная таблицаself.tmp_assigned_squad = {}self.tmp_entered_squad = {}printf("CREATE NEW SIM BOARD [%s]", tostring(self.sid))endfunction sim_board:start_sim()self.simulation_started = trueendfunction sim_board:stop_sim()self.simulation_started = falseend-- Перевод игрока в группировку.function sim_board:set_actor_community(community)---- Устанавливаем группировку игрокаdb.actor:set_character_community(actor_communitites[community], 0, 0)end--' Регистрация нового смарта.function sim_board:register_smart(obj)printf("register_smart %s", obj:name())if self.smarts[obj.id] ~= nil thenabort("Smart already exist in list [%s]", obj:name())endself.smarts[obj.id] = {smrt = obj, squads = {}, stayed_squad_quan = 0}self.smarts_by_names[obj:name()] = objend-- Инициализация смартаfunction sim_board:init_smart(obj)if self.tmp_assigned_squad[obj.id] ~= nil thenfor k,v in pairs(self.tmp_assigned_squad[obj.id]) doself:assign_squad_to_smart(v, obj.id)endself.tmp_assigned_squad[obj.id] = nilendif self.tmp_entered_squad[obj.id] ~= nil thenfor k,v in pairs(self.tmp_entered_squad[obj.id]) doself:enter_smart(v, obj.id)endself.tmp_entered_squad[obj.id] = nilendend--' АнРегистрация смарта.function sim_board:unregister_smart(obj)if self.smarts[obj.id] == nil thenabort("Trying to unregister nil smart [%s]", obj:name())endself.smarts[obj.id] = nilend--' Создание нового отрядаfunction sim_board:create_squad(spawn_smart, sq_id)printf("create squad called")local squad_id = tostring(sq_id)local squad = alife():create(squad_id,spawn_smart.position,spawn_smart.m_level_vertex_id,spawn_smart.m_game_vertex_id)--local squad = squad_class(self, squad_id, faction_name, settings_id)--squad:init_squad(spawn_smart)printf("Creating squad[%s] in smart[%s]", squad_id, spawn_smart:name())--' Определяем в каком смарте создать новый отрядsquad:create_npc(spawn_smart)squad:set_squad_relation()self:assign_squad_to_smart(squad, spawn_smart.id)--' Пересчитываем Team, Squad, Groupfor k in squad:squad_members() dolocal obj = k.objectsquad.board:setup_squad_and_group(obj)endreturn squadend--' Удалить отрядfunction sim_board:remove_squad(squad)printf("Remove squad %s", tostring(squad.id))if squad.current_action == nil orsquad.current_action.dest_smrt == nilthensquad.board:exit_smart(squad, squad.smart_id)end--squad:hide()self:assign_squad_to_smart(squad, nil)squad:remove_squad()end--' Назначение отряда в смарт.function sim_board:assign_squad_to_smart(squad, smart_id)-- Если смарта нету (например на загрузке он еще не загружен), то мы загоняем данные-- во временную таблицу. И на загрузке смарта автодобавляем их.--printf("assigned squad %s to smart [%s].", tostring(squad.id), tostring(smart_id))if smart_id ~= nil and self.smarts[smart_id] == nil then-- printf(" to tmp")if self.tmp_assigned_squad[smart_id] == nil thenself.tmp_assigned_squad[smart_id] = {}endtable.insert(self.tmp_assigned_squad[smart_id], squad)returnend--' Убираем отряд из старого смартаlocal old_smart_id = nilif squad.smart_id ~= nil thenold_smart_id = squad.smart_idendif old_smart_id ~= nil and self.smarts[old_smart_id] ~= nil thenself.smarts[old_smart_id].squads[squad.id] = nilself.smarts[old_smart_id].smrt:refresh()endif smart_id == nil thensquad:assign_smart(nil)returnendsquad:assign_smart(self.smarts[smart_id].smrt)--' Прописываем отряд в новом смарте.self.smarts[smart_id].squads[squad.id] = squadself.smarts[smart_id].smrt:refresh()end--' Отряд покидает смарт (уменьшаются ресурсы)function sim_board:exit_smart(squad, smart_id)if smart_id == nil thenreturnendif squad.entered_smart ~= smart_id thenreturnendsquad.entered_smart = nillocal smart = self.smarts[smart_id]if smart == nil thenabort("Smart nil while smart_id not nil [%s]", tostring(smart_id))endprintf("Squad %s exit smart %s. Quan = %s", tostring(squad.id), smart.smrt:name(), tostring(smart.stayed_squad_quan))smart.stayed_squad_quan = smart.stayed_squad_quan - 1smart.squads[squad.id] = nil--smart.smrt:refresh()end--' Отряд занимает смарт (увеличиваются ресурсы)function sim_board:enter_smart(squad, smart_id, after_load)callstack()if self.smarts[smart_id] == nil thenprintf(" to tmp")if self.tmp_entered_squad[smart_id] == nil thenself.tmp_entered_squad[smart_id] = {}endtable.insert(self.tmp_entered_squad[smart_id], squad)returnendlocal smart = self.smarts[smart_id]if squad.entered_smart ~= nil thenabort("Couldn enter to smart, becouse i'm not leave old one. Squad [%s]", squad.id)endsquad.entered_smart = smart_idprintf("Squad %s enter smart %s. Quan = %s", tostring(squad.id), smart.smrt:name(), tostring(smart.stayed_squad_quan))--smart.smrt:refresh()smart.stayed_squad_quan = smart.stayed_squad_quan + 1squad.items_spawned = falseend-- установить squad и group в соответствии с работойfunction sim_board:setup_squad_and_group(obj)--printf("tsg["..obj:name().."]")local level_name = level.name()--' Группу берем из уровня.local obj = alife():object(obj.id)local group = group_id_by_levels[level_name] or 0change_team_squad_group(obj, obj.team, obj.squad, group)--' Сквад берем из смарта.local squad = alife():object(obj.group_id)if squad == nil thenchange_team_squad_group(obj, obj.team, 0, obj.group)--printf("TSG1: [%s][%s][%s]", tostring(obj.team), tostring(obj.squad), tostring(obj.group))returnendlocal smart = nilif squad.current_action ~= nil and squad.current_action.name == "reach_target" thensmart = alife():object(squad.assigned_target_id)elseif squad.smart_id ~= nil thensmart = alife():object(squad.smart_id)endif smart == nil thenchange_team_squad_group(obj, obj.team, 0, obj.group)--printf("TSG2: [%s][%s][%s]", tostring(obj.team), tostring(obj.squad), tostring(obj.group))returnendlocal obj_sq = 0if smart:clsid() == clsid.smart_terrain thenobj_sq = smart.squad_idendchange_team_squad_group(obj, obj.team, obj_sq, obj.group)--printf("TSG3: [%s][%s][%s]", tostring(obj.team), tostring(obj.squad), tostring(obj.group))end--' Заполнение стартового расположенияfunction sim_board:fill_start_position()if self.start_position_filled == true thenreturnend--printf("FILL START POSITION [%s]", self.player_name)self.start_position_filled = truefor level in game_graph():levels() dolocal section_name = "start_position_" .. alife():level_name(level.id)if not setting_ini:section_exist(section_name) thenreturnendlocal n = setting_ini:line_count(section_name)for i=0,n-1 dolocal result, id, value = setting_ini:r_line(section_name,i,"","")local smrt_names = utils.parse_names(value)for k,v in pairs(smrt_names) dolocal smart = self.smarts_by_names[v]if smart == nil thenabort("Wrong smart name [%s] in start position", tostring(v))endlocal squad = self:create_squad(smart, id)self:enter_smart(squad, smart.id)--squad:update()endendendend--' Возвратить смарт по его имени.function sim_board:get_smart_by_name(name)return self.smarts_by_names[name]end--' Возвращает количество отрядов в смарте.function sim_board:get_smart_population(smart)return self.smarts[smart.id].stayed_squad_quanend--' Получение игрового поля.function get_sim_board()if board == nil thenboard = sim_board()endreturn boardendfunction sim_board:get_squad_target(squad)--printf("List of available target for %s", squad.id)local available_targets = {}local most_priority_task = nillocal max_prior = 0for k,v in pairs(simulation_objects.get_sim_obj_registry().objects) dolocal curr_prior = 0-- Проверка против выдачи таска на себя.if v.id ~= squad.id thencurr_prior = v:evaluate_prior(squad)endif curr_prior > 0 thenlocal target_tbl = {prior = curr_prior, target = v}table.insert(available_targets, target_tbl)endendif #available_targets > 0 thentable.sort(available_targets, function(a, return a.prior > b.prior end)local max_id = math.floor(0.3 * #available_targets)if max_id == 0 then max_id = 1 endmost_priority_task = available_targets[math.random(max_id)].targetend--print_table(available_targets)--printf("end of List of available target for %s", squad.id)return most_priority_task or (squad.smart_id and alife():object(squad.smart_id)) or squadendlocal targets_by_squad_id = {}--[[function sim_board:reset_targets()for k,v in pairs(self.squads) doend]]----' Обнуление списка на создании игры.function clear()board = nilend--' Тестовые функцииfunction print()--print_table(get_sim_board().smarts)end local DEATH_IDLE_TIME = 10*60 -- секундlocal RESPAWN_IDLE = 1000 -- секунд игрового времениlocal RESPAWN_RADIUS = 150 -- радиус респауна(если актер ближе, то не спаунить)SMART_TERRAIN_SECT = "smart_terrain"smart_terrains_by_name = {}local locations_ini = ini_file("misc\\smart_terrain_masks.ltx")nearest_to_actor_smart = {id = nil , dist = math.huge}local path_fields = { "path_walk", "path_main", "path_home", "center_point" }local valid_territory = {default = true,base = true,resource = true,territory = true}--' Проверка, что нпс подходит работеlocal function job_avail_to_npc(npc_info, job_info, smart)--printf("job_avail_to_npc %s job %s smart %s", npc_info.se_obj:name(), tostring(job_info.job_id), smart:name())local job = smart.job_data[job_info.job_id]if job ~= nil thenjob = job.sectionendif smart.dead_time[job_info.job_id] ~= nil thenreturn falseend-- Проверка условия "монстровости"if job_info._precondition_is_monster ~= nil and job_info._precondition_is_monster ~= npc_info.is_monster thenreturn falseend--' Проверяем подходит ли нпс по предикатуif job_info._precondition_function ~= nil thenif not job_info._precondition_function(npc_info.se_obj, smart, job_info._precondition_params, npc_info) thenreturn falseendendreturn trueend-- Итерируемся по НПС, начинаем со свободных нпс, потом НПС на низкоприоритетных работах, потом на высокоприоритетных.-- Для каждого конкретного НПС ищем работу.-- Отсеиваем в поиске работы, приоритет которых ниже, чем у текущей.local function job_iterator(jobs, npc_data, selected_job_prior, smart)--printf(" iterate")-- итерируемся по работамlocal current_job_prior = selected_job_priorlocal selected_job_id = nillocal selected_job_link = nilfor k,v in pairs(jobs) do-- Если приоритет у проверяемой работы ниже, чем приоритет текущей выбранной работы НПС - завершаем выполнениеif current_job_prior > v._prior thenreturn selected_job_id, current_job_prior, selected_job_linkend-- Проверяем, может ли НПС занять данную работуif job_avail_to_npc(npc_data, v, smart) then-- Это работа-кластер или работа-описание.if v.job_id == nil then-- Вызываем рекурсивно себя для списка работ кластераselected_job_id, current_job_prior, selected_job_link = job_iterator(v.jobs, npc_data, selected_job_prior, smart)else-- Если работа пустая или ее занимаем мы сами - выбираем ее.if v.npc_id == nil thenreturn v.job_id, v._prior, velseif v.job_id == npc_data.job_id thenreturn v.job_id, v._prior, vendendendendreturn selected_job_id, current_job_prior, selected_job_linkend-- Расстояние до работыlocal function arrived_to_smart(obj, smart)local obj_gv, obj_poslocal storage = db.storage[obj.id]if storage == nil thenobj_gv, obj_pos = game_graph():vertex(obj.m_game_vertex_id), obj.positionelselocal obj = db.storage[obj.id].objectobj_gv, obj_pos = game_graph():vertex(obj:game_vertex_id()), obj:position()endlocal smart_gv = game_graph():vertex(smart.m_game_vertex_id)if obj.group_id thenlocal squad = smart.board.squads[obj.group_id]if squad ~= nil and squad.current_action thenif squad.current_action.name == "reach_target" thenlocal squad_target = simulation_objects.get_sim_obj_registry().objects[squad.assigned_target_id]if squad_target ~= nil thenreturn squad_target:am_i_reached(squad)elsereturn alife():object(squad.assigned_target_id):am_i_reached(squad)endelseif squad.current_action.name == "stay_point" thenreturn trueendendendif obj_gv:level_id() == smart_gv:level_id() thenreturn obj_pos:distance_to_sqr(smart.position) <= 10000 --Ближе 100 метровelsereturn falseendend------------------------------------------------------------------------------------------------------------------------ Класс "se_smart_terrain". Обеспечивает поддержку smart terrain в ОФЛАЙНЕ.----------------------------------------------------------------------------------------------------------------------class "se_smart_terrain" (cse_alife_smart_zone)function se_smart_terrain:__init(section) super(section)self.initialized = falseself.b_registred = falseself.population = 0self.npc_to_register = {}self.npc_by_job_section = {}self.dead_time = {}-- Таблица для хранения зарегистренных НПСself.npc_info = {} -- Те, кто уже пришел и стал на работуself.arriving_npc = {} -- Только идущие на работу.endfunction se_smart_terrain:on_before_register()cse_alife_smart_zone.on_before_register(self)self.board = sim_board.get_sim_board()self.board:register_smart(self)self.smart_level = alife():level_name(game_graph():vertex(self.m_game_vertex_id):level_id())--printf("SMARTLEVEL %s level %s", self:name(), tostring(self.smart_level))endfunction se_smart_terrain:on_register()cse_alife_smart_zone.on_register(self)-- Проверяем кастомдату обьекта на наличие стори айди.story_objects.check_spawn_ini_for_story_id(self)simulation_objects.get_sim_obj_registry():register(self)printf("register smart %s", self:name())if dev_dedug thenself:refresh()endprintf("Returning alife task for object [%s] game_vertex [%s] level_vertex [%s] position %s", self.id, self.m_game_vertex_id, self.m_level_vertex_id, vec_to_str(self.position))self.smart_alife_task = CALifeSmartTerrainTask(self.m_game_vertex_id, self.m_level_vertex_id)smart_terrains_by_name[self:name()] = selfself.b_registred = trueself:load_jobs()self.board:init_smart(self)if self.need_init_npc == true thenself.need_init_npc = falseself:init_npc_after_load()end-- Регистрим персонажей, которые добавили до регистрации смарта. (отложенный список)self:register_delayed_npc()self.check_time = time_global()end-- анрегистрация объекта в симуляторе.-- вызывается симулятором.function se_smart_terrain:on_unregister()cse_alife_smart_zone.on_unregister(self)self.board:unregister_smart(self)smart_terrains_by_name[self:name()] = nilunregister_story_object_by_id(self.id)simulation_objects.get_sim_obj_registry():unregister(self)end-- чтение custom data.function se_smart_terrain:read_params()self.ini = self:spawn_ini()if not self.ini:section_exist( SMART_TERRAIN_SECT ) thenabort( "[smart_terrain %s] no configuration!", self:name() )self.disabled = truereturnendlocal filename = utils.cfg_get_string(self.ini, SMART_TERRAIN_SECT, "cfg", self, false, "")local fs = getFS()if filename thenif fs:exist("$game_config$",filename) thenself.ini = ini_file(filename)elseabort("There is no configuration file [%s] in smart_terrain [%s]", filename, self:name())endendlocal ini = self.iniself.sim_type = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "sim_type", self, false, "", "default")--' Вычитка симуляционных свойствif valid_territory[self.sim_type] == nil thenabort("Wrong sim_type value [%s] in smart [%s]", self.sim_type, self:name())endself.squad_id = utils.cfg_get_number(ini, SMART_TERRAIN_SECT, "squad_id", self, false, 0)self.respawn_sector = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "respawn_sector", self, false, "")self.respawn_radius = utils.cfg_get_number(ini, SMART_TERRAIN_SECT, "respawn_radius", self, false, 150)if self.respawn_sector ~= nil thenif self.respawn_sector == "default" thenself.respawn_sector = "all"endself.respawn_sector = xr_logic.parse_condlist(nil, SMART_TERRAIN_SECT, "respawn_sector", self.respawn_sector)endself.mutant_lair = utils.cfg_get_bool(ini, SMART_TERRAIN_SECT, "mutant_lair", self, false)self.no_mutant = utils.cfg_get_bool(ini, SMART_TERRAIN_SECT, "no_mutant", self, false)if self.no_mutant == true thenprintf("Found no mutant point %s", self:name())endself.forbidden_point = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "forbidden_point", self, false, "")--' Рестрикторы для симуляцииself.def_restr = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "def_restr", self, false, "", nil)self.att_restr = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "att_restr", self, false, "", nil)self.safe_restr = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "safe_restr", self, false, "", nil)self.spawn_point = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "spawn_point", self, false, "")self.arrive_dist = utils.cfg_get_number(ini, SMART_TERRAIN_SECT, "arrive_dist", self, false, 30)-- self.max_population = utils.cfg_get_number(ini, SMART_TERRAIN_SECT, "max_population", self, false, 0)local max_population = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "max_population", self, false, "", 0)local parsed_condlist = xr_logic.parse_condlist(nil, SMART_TERRAIN_SECT, "max_population", max_population)self.max_population = tonumber(xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, parsed_condlist))-- self.sim_avail = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "sim_avail", self, false, "")-- if self.sim_avail ~= nil then-- self.sim_avail = xr_logic.parse_condlist(nil, SMART_TERRAIN_SECT, "sim_avail", self.sim_avail)-- endlocal respawn_params = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "respawn_params", self, false, "", nil)self.respawn_only_smart = utils.cfg_get_bool(ini, SMART_TERRAIN_SECT, "respawn_only_smart", self, false, false)local smart_control_section = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "smart_control", self, false, "", nil)if smart_control_section ~= nil thenself.base_on_actor_control = smart_terrain_control.CBaseOnActorControl(self, ini, smart_control_section)endself.respawn_point = falseif respawn_params ~= nil thenself:check_respawn_params(respawn_params)endif level.patrol_path_exists(self:name() .. "_traveller_actor") thenprintf("Smart_terrain [%s] has no traveller_actor path!!!!!", self:name())self.traveler_actor_path = self:name() .. "_traveller_actor"endif level.patrol_path_exists(self:name() .. "_traveller_squad") thenprintf("Smart_terrain [%s] has no traveller_squad path!!!!!", self:name())self.traveler_squad_path = self:name() .. "_traveller_squad"endif not locations_ini:section_exist(self:name()) thenprintf("! SMART_TERRAIN [%s] has no terrain_mask section in smart_terrain_masks.ltx!!!",self:name())endend--*******************************************************-- МЕТОДЫ ДЛЯ РАБОТЫ С НПС--*******************************************************-- заполнить информацию о персонаже-- у монстров нету метода profile_name()function se_smart_terrain:fill_npc_info(obj)local npc_info = {}printf("filling npc_info for obj [%s]", tostring(obj:name()))local is_stalker = IsStalker(obj)npc_info.se_obj = objnpc_info.is_monster = not is_stalkernpc_info.need_job = "nil" -- Специально для смены гвардов. Указывает на какую работу хочет данный чувак.npc_info.job_prior = -1npc_info.job_id = -1npc_info.begin_job = falseif is_stalker thennpc_info.stype = modules.stype_stalkerelsenpc_info.stype = modules.stype_mobileendreturn npc_infoendfunction se_smart_terrain:refresh_script_logic(obj_id)local object = alife():object(obj_id)local stype = modules.stype_mobileif IsStalker(object) thenstype = modules.stype_stalkerendxr_logic.initialize_obj(db.storage[object.id].object, db.storage[object.id], false, db.actor, stype)end-- добавить npc в smart terrain.function se_smart_terrain:register_npc(obj)printf("[smart_terrain %s] register called obj=%s", self:name(), obj:name())self.population = self.population + 1if self.b_registred == false thentable.insert(self.npc_to_register, obj)returnend-- Только для монстров, чтобы ходили по смартам.if not IsStalker(obj) thenobj:smart_terrain_task_activate()endobj.m_smart_terrain_id = self.idif arrived_to_smart(obj, self) thenself.npc_info[obj.id] = self:fill_npc_info(obj)-- Затычка на случай если мы регистримся в смарт, из которого только что сами вынесли всех врагов.self.dead_time = {}-- тут надо найти чуваку работуself:select_npc_job(self.npc_info[obj.id])elseself.arriving_npc[obj.id] = objendend-- Регистрация НПС в список отложенных. Осуществляется на загрузке или на регистрации НПС, пока не зарегистрен смартfunction se_smart_terrain:register_delayed_npc()for k,v in pairs(self.npc_to_register) doself:register_npc(v)endself.npc_to_register = {}end-- отпустить npcfunction se_smart_terrain:unregister_npc(obj)--callstack()printf("smart [%s] unregister npc [%s]", self:name(), obj:name())self.population = self.population - 1if self.npc_info[obj.id] ~= nil then-- TODO: Тут надо выгнать чувака с занимаемой им работыself.npc_info[obj.id].job_link.npc_id = nilself.npc_info[obj.id] = nilobj:clear_smart_terrain()if db.storage[obj.id] ~= nil thenlocal object = db.storage[obj.id].objectlocal stype = modules.stype_mobileif IsStalker(obj) thenstype = modules.stype_stalkerendxr_logic.initialize_obj(object, db.storage[obj.id], false, db.actor, stype)endreturnendif self.arriving_npc[obj.id] ~= nil thenself.arriving_npc[obj.id] = nilobj:clear_smart_terrain()returnendabort("self.npc_info[obj.id] = nil !!! obj.id=%d", obj.id)end-- Убрать убитогоfunction se_smart_terrain:clear_dead(obj)if self.npc_info[obj.id] ~= nil then-- Устанавливаем таймер смерти на работеself.dead_time[self.npc_info[obj.id].job_id] = game.get_game_time()self.npc_info[obj.id].job_link.npc_id = nilself.npc_info[obj.id] = nilobj:clear_smart_terrain()returnendif self.arriving_npc[obj.id] ~= nil thenself.arriving_npc[obj.id] = nilobj:clear_smart_terrain()returnendabort("self.npc_info[obj.id] = nil !!! obj.id=%d", obj.id)end-- выдать объекту задание.function se_smart_terrain:task(obj)if self.arriving_npc[obj.id] ~= nil thenreturn self.smart_alife_taskendreturn self.job_data[self.npc_info[obj.id].job_id].alife_taskend--*******************************************************-- Функции для работы с работами--*******************************************************-- Загрузка работ (из gulag_general)function se_smart_terrain:load_jobs()--printf("LOAD JOBS %s", self:name())-- Загружаем иерархию работself.jobs = gulag_general.load_job(self)-- Загружаем ltx работ.self.ltx, self.ltx_name = xr_gulag.loadLtx(self:name())-- Сортируем всю иерархию по уменьшению приоритета-- Рекурсивная функция сортировкиlocal function sort_jobs(jobs)for k,v in pairs(jobs) doif v.jobs ~= nil thensort_jobs(v.jobs)endendtable.sort(jobs, function(a, return a._prior > b._prior end )end-- if self:name() == "jup_a10_smart_terrain" then-- printf("before sort")-- store_table(self.jobs)-- endsort_jobs(self.jobs)--if self:name() == "jup_a10_smart_terrain" then-- printf("after sort")-- store_table(self.jobs)--end-- Надо сделать постобработку работ. Проинитить все неиниченные поля-- Для более быстрого доступа нужно вычленить параметры работ в отдельную таблицу вида:--self.job_data[job_id] = {}local id = 0self.job_data = {}local function get_jobs_data(jobs)for k,v in pairs(jobs) doif v.jobs ~= nil thenget_jobs_data(v.jobs)elseif v.job_id == nil thenprint_table(self.jobs)abort("Incorrect job table")endself.job_data[id] = v.job_idself.job_data[id]._prior = v._prior -- Кешируем для проверкиv.job_id = idid = id + 1endendendget_jobs_data(self.jobs)-- Пробегаемся по работам и высчитываем для каждой работы alife_taskfor k,v in pairs(self.job_data) dolocal section = v.sectionlocal ltx = v.ini_file or self.ltxif not ltx:line_exist(section, "active") thenabort("gulag: ltx=%s no 'active' in section %s", self.ltx_name, section)endlocal active_section = ltx:r_string(section, "active")-- printf("job_type %s job_section %s", tostring(v.job_type), tostring(section))-- В зависимости от типа работы по разному считаем alife_pathif v.job_type == "path_job" then -- работа задается патрульным путемlocal path_fieldfor i,vv in pairs(path_fields) doif ltx:line_exist(active_section, vv) thenpath_field = vvbreakendend--printf("path_field %s prefix_name %s active_section %s", tostring(path_field), tostring(v.prefix_name), tostring(active_section))local path_name = ltx:r_string(active_section, path_field)if v.prefix_name ~= nil thenpath_name = v.prefix_name .. "_" .. path_nameelsepath_name = self:name() .. "_" .. path_nameendif path_field == "center_point" then --' TODO убрать затык когда переделаем кемпы на смарткаверыif level.patrol_path_exists(path_name .. "_task") thenpath_name = path_name .. "_task"endendv.alife_task = CALifeSmartTerrainTask(path_name)elseif v.job_type == "smartcover_job" then -- работа задается смарткаверомlocal smartcover_name = ltx:r_string(active_section, "cover_name")local smartcover = se_smart_cover.registered_smartcovers[smartcover_name]if smartcover == nil thenabort("There is an exclusive job with wrong smatrcover name [%s] smartterrain [%s]", tostring(smartcover_name), self:name())endprintf("Returning alife task for object [%s] game_vertex [%s] level_vertex [%s] position %s", smartcover.id, smartcover.m_game_vertex_id, smartcover.m_level_vertex_id, vec_to_str(smartcover.position))v.alife_task = CALifeSmartTerrainTask(smartcover.m_game_vertex_id, smartcover.m_level_vertex_id)elseif v.job_type == "point_job" then -- работа задается позициейv.alife_task = self.smart_alife_taskendv.game_vertex_id = v.alife_task:game_vertex_id()v.level_id = game_graph():vertex(v.game_vertex_id):level_id()v.position = v.alife_task:position()endend-- Апдейт работ смарттеррейна.-- Если передается object, то значит нужно найти только для негоfunction se_smart_terrain:update_jobs()self:check_alarm()--printf("UPDATE JOBS %s", self:name())-- Проверяем, дошел ли кто-то до смартаfor k,v in pairs(self.arriving_npc) doif arrived_to_smart(v, self) thenself.npc_info[v.id] = self:fill_npc_info(v)-- Затычка на случай если мы регистримся в смарт, из которого только что сами вынесли всех врагов.self.dead_time = {}-- тут надо найти чуваку работуself:select_npc_job(self.npc_info[v.id])self.arriving_npc[k] = nilendend-- Сортируем НПС по увеличению приоритета занимаемой работыtable.sort(self.npc_info, function(a, return a.job_prior < b.job_prior end )for k,v in pairs(self.npc_info) doself:select_npc_job(v)endend-- Выбор работы для персонажаfunction se_smart_terrain:select_npc_job(npc_info)-- Выбираем работуlocal selected_job_id, selected_job_prior, selected_job_link = job_iterator(self.jobs, npc_info, 0, self)if selected_job_id == nil thenprint_table(self.jobs)abort("Insufficient smart_terrain jobs %s", self:name())end-- Назначаем работуif selected_job_id ~= npc_info.job_id and selected_job_link ~= nil then-- Установить себе выбранную работу--printf("NPC %s FOUND JOB %s SECTION %s", npc_info.se_obj:name(), selected_job_id, self.job_data[selected_job_link.job_id].section)-- Если НПС был на работе - выгоняем его с нее.if npc_info.job_link ~= nil thenself.npc_by_job_section[self.job_data[npc_info.job_link.job_id].section] = nilnpc_info.job_link.npc_id = nilendselected_job_link.npc_id = npc_info.se_obj.idself.npc_by_job_section[self.job_data[selected_job_link.job_id].section] = selected_job_link.npc_idnpc_info.job_id = selected_job_link.job_idnpc_info.job_prior = selected_job_link._priornpc_info.begin_job = false-- сохраняем ссылку на работу, для облегчения удаленияnpc_info.job_link = selected_job_link-- завершаем текущую работуlocal obj_storage = db.storage[npc_info.se_obj.id]if obj_storage ~= nil thenxr_logic.switch_to_section(obj_storage.object, self.ltx, "nil")endendif npc_info.begin_job ~= true then-- Проверяем, дошел ли персонаж до работы (то есть может ли он начать ее выполнение)local job_data = self.job_data[npc_info.job_id]-- Начинаем выполнять работуprintf("[smart_terrain %s] gulag: beginJob: obj=%s job= %s", self:name(), npc_info.se_obj:name(), job_data.section)-- Смена работы, очищаем память для оффлайнового обьекта.db.offline_objects[npc_info.se_obj.id] = {}npc_info.begin_job = truelocal obj_storage = db.storage[npc_info.se_obj.id]if obj_storage ~= nil thenself:setup_logic(obj_storage.object)endendend-- настроить логику для объекта, который в онлайне.function se_smart_terrain:setup_logic(obj)--printf("setup npc logic %s", obj:name())-- callstack()local npc_data = self.npc_info[obj:id()]local job = self.job_data[npc_data.job_id]local ltx = job.ini_file or self.ltxlocal ltx_name = job.ini_path or self.ltx_namexr_logic.configure_schemes(obj, ltx, ltx_name, npc_data.stype, job.section, job.prefix_name or self:name())local sect = xr_logic.determine_section_to_activate(obj, ltx, job.section, db.actor)if utils.get_scheme_by_section(job.section) == "nil" thenabort("[smart_terrain %s] section=%s, don't use section 'nil'!", self:name(), sect)endxr_logic.activate_by_section(obj, ltx, sect, job.prefix_name or self:name(), false)end-- получить работу, которую занимает объектfunction se_smart_terrain:getJob(obj_id)return self.npc_info[obj_id] and self.job_data[self.npc_info[obj_id].job_id]end-- Получение персонажа, который занимает указанную работу.function se_smart_terrain:idNPCOnJob(job_name)return self.npc_by_job_section[job_name]endfunction se_smart_terrain:switch_to_desired_job(npc)-- Берем текущую работу НПСlocal npc_id = npc:id()local npc_info = self.npc_info[npc_id]--printf("***** %s -> %s", npc:name(), tostring(npc_info.need_job))local changing_npc_id = self.npc_by_job_section[npc_info.need_job]--printf("changing_npc_id %s", tostring(changing_npc_id))if changing_npc_id == nil then-- Мы не нашли с кем меняться, просто ресетим себяself.npc_info[npc_id].job_link = nilself.npc_info[npc_id].job_id = -1self.npc_info[npc_id].job_prior = -1self:select_npc_job(self.npc_info[npc_id])--print_table(self.npc_by_job_section)--abort("ERROR during channging NPC")returnendif self.npc_info[changing_npc_id] == nil then-- Мы не нашли с кем меняться, просто ресетим себяself.npc_info[npc_id].job_link = nilself.npc_info[npc_id].job_id = -1self.npc_info[npc_id].job_prior = -1self:select_npc_job(self.npc_info[npc_id])--print_table(self.npc_by_job_section)--abort("ERROR during channging NPC")returnendlocal desired_job = self.npc_info[changing_npc_id].job_id-- Переключаем НПС на желаемую работуif npc_info.job_link ~= nil thenself.npc_by_job_section[self.job_data[npc_info.job_link.job_id].section] = nilnpc_info.job_link.npc_id = nilendlocal selected_job_link = self.npc_info[changing_npc_id].job_linkselected_job_link.npc_id = npc_info.se_obj.idself.npc_by_job_section[self.job_data[selected_job_link.job_id].section] = selected_job_link.npc_idnpc_info.job_id = selected_job_link.job_idnpc_info.job_prior = selected_job_link._priornpc_info.begin_job = true-- сохраняем ссылку на работу, для облегчения удаленияnpc_info.job_link = selected_job_linknpc_info.need_job = "nil"local obj_storage = db.storage[npc_id]if obj_storage ~= nil thenself:setup_logic(obj_storage.object)end-- Освобождаем НПС, который занимает желаемую работу и говорим ему перевыбрать работуself.npc_info[changing_npc_id].job_link = nilself.npc_info[changing_npc_id].job_id = -1self.npc_info[changing_npc_id].job_prior = -1self:select_npc_job(self.npc_info[changing_npc_id])end--*******************************************************-- СЕЙВ/ЛОАД--*******************************************************-- сохранениеfunction se_smart_terrain:STATE_Write(packet)cse_alife_smart_zone.STATE_Write(self, packet)set_save_marker(packet, "save", false, "se_smart_terrain")-- Информацию о НПС, идущих в смартlocal n = 0for k,v in pairs(self.arriving_npc) don = n + 1endpacket:w_u8(n)for k,v in pairs(self.arriving_npc) dopacket:w_u16(k)end-- Информацию о НПС в смартеn = 0for k,v in pairs(self.npc_info) don = n + 1endpacket:w_u8(n)for k,v in pairs(self.npc_info) dopacket:w_u16(k)packet:w_u8(v.job_prior)packet:w_u8(v.job_id)packet:w_bool(v.begin_job)packet:w_stringZ(v.need_job)endn = 0for k,v in pairs(self.dead_time) don = n + 1endpacket:w_u8(n)for k,v in pairs(self.dead_time) dopacket:w_u8(k)utils.w_CTime(packet, v)endif self.base_on_actor_control ~= nil thenpacket:w_bool(true)self.base_on_actor_control:save(packet)elsepacket:w_bool(false)endif self.respawn_point thenpacket:w_bool(true)local n = 0for k,v in pairs(self.already_spawned) don = n + 1endpacket:w_u8(n)for k,v in pairs(self.already_spawned) dopacket:w_stringZ(k)packet:w_u8(v.num)endif self.last_respawn_update ~= nil thenpacket:w_bool(true)utils.w_CTime(packet, self.last_respawn_update)elsepacket:w_bool(false)endelsepacket:w_bool(false)endif self.population < 0 thenabort("Smart_terrain [%s] population can't be less than zero!!!", self:name())endpacket:w_u8(self.population)set_save_marker(packet, "save", true, "se_smart_terrain")end-- восстановлениеfunction se_smart_terrain:STATE_Read(packet, size)cse_alife_smart_zone.STATE_Read(self, packet, size)-- под LevelEditor не пытаться читать из пакета ничегоif editor() thenreturnendset_save_marker(packet, "load", false, "se_smart_terrain")self:read_params()-- Информацию о НПС, идущих в смартlocal n = packet:r_u8()self.arriving_npc = {}for i = 1,n dolocal id = packet:r_u16()self.arriving_npc[id] = falseend-- Информацию о НПС в смартеn = packet:r_u8()--printf("load %s npc", tostring(n))self.npc_info = {}for i = 1,n dolocal id = packet:r_u16()--printf("__ id %s", tostring(id))self.npc_info[id] = {}local npc_info = self.npc_info[id]npc_info.job_prior = packet:r_u8()--printf("__ job_prior %s", tostring(npc_info.job_prior))if npc_info.job_prior == 255 thennpc_info.job_prior = -1endnpc_info.job_id = packet:r_u8()--printf("__ job_id %s", tostring(npc_info.job_id))if npc_info.job_id == 255 thennpc_info.job_id = -1endnpc_info.begin_job = packet:r_bool()--printf("__ begin_job %s", tostring(npc_info.begin_job))npc_info.need_job = packet:r_stringZ()endn = packet:r_u8()self.dead_time = {}--printf("load %s dead_time", tostring(n))for i =1,n dolocal job_id = packet:r_u8()--printf("__ job_id %s", tostring(job_id))local dead_time = utils.r_CTime(packet)self.dead_time[job_id] = dead_timeendself.need_init_npc = trueif self.script_version > 9 thenif packet:r_bool() == true then--self.base_on_actor_controlself.base_on_actor_control:load(packet)endendlocal respawn_point = packet:r_bool()--printf("LOAD RESPAWN %s", self:name())if respawn_point thenn = packet:r_u8()for i = 1, n dolocal id = packet:r_stringZ()local num = packet:r_u8()self.already_spawned[id].num = numendif self.script_version > 11 thenlocal exist = packet:r_bool()if exist thenself.last_respawn_update = utils.r_CTime(packet)elseself.last_respawn_update = nilendendendself.population = packet:r_u8()set_save_marker(packet, "load", true, "se_smart_terrain")end-- Инициализация НПС после загрузки.function se_smart_terrain:init_npc_after_load()local function find_job(jobs, npc_info)for k,v in pairs(jobs) doif v.jobs ~= nil thenfind_job(v.jobs, npc_info)elseif v.job_id == npc_info.job_id thennpc_info.job_link = vv.npc_id = npc_info.se_obj.idreturnendendendendlocal sim = alife()--printf("[%s] init_npc_after_load", self:name())for k,v in pairs(self.arriving_npc) dolocal sobj = sim:object(k)if sobj ~= nil thenself.arriving_npc[k] = sobjelseself.arriving_npc[k] = nilendendfor k,v in pairs(self.npc_info) dolocal sobj = sim:object(k)if sobj ~= nil thenlocal npc_info = self:fill_npc_info(sobj)npc_info.job_prior = v.job_priornpc_info.job_id = v.job_idnpc_info.begin_job = v.begin_jobnpc_info.need_job = v.need_job--Теперь надо найти данную работу и выставить ссылку на нее.find_job(self.jobs, npc_info)self.npc_info[k] = npc_infoif npc_info.job_link ~= nil thenself.npc_by_job_section[self.job_data[npc_info.job_link.job_id].section] = kendelseself.npc_info[k] = nilendendend--' Возвращает отформатированную строку свойств смартаfunction se_smart_terrain:get_smart_props()local props = smart_names.get_smart_terrain_name(self)if(props==nil) or (_G.dev_debug) thenprops = self:name().." ["..self.id.."]\\n"..self.sim_type.."\\n".."squad_id = "..tostring(self.id).."\\n".."capacity = "..tostring(self.max_population).." ("..sim_board.get_sim_board():get_smart_population(self)..")\\n"if self.respawn_point ~= nil and self.already_spawned ~= nil thenprops = props.."\\nalready_spawned :\n"for k,v in pairs(self.already_spawned) doprops = props.."["..k.."] = "..v.num.."("..xr_logic.pick_section_from_condlist(db.actor, nil,self.respawn_params[k].num)..")\\n"endif self.last_respawn_update thenprops = props.."\\ntime_to_spawn:"..tostring(RESPAWN_IDLE - game.get_game_time():diffSec(self.last_respawn_update)).."\\n"endend--' Добавляем информацию о находящихся в смарте отрядахfor k,v in pairs(sim_board.get_sim_board().smarts[self.id].squads) doprops = props .. tostring(v.id) .. "\\n"endendreturn propsend--' Отрисовка смарта на игровом полеfunction se_smart_terrain:show()local time = time_global()if(self.showtime~=nil) and (self.showtime+200>=time) thenreturnendself.showtime = timelocal player = self.player_namelocal spot = "neutral"if self.sim_avail == nil or xr_logic.pick_section_from_condlist(db.actor or alife():actor(), self, self.sim_avail) == "true" thenspot = "friend"elsespot = "enemy"endif(self.smrt_showed_spot==spot) thenlevel.map_change_spot_hint(self.id, "alife_presentation_smart_"..self.sim_type.."_"..self.smrt_showed_spot, self:get_smart_props())returnendif(_G.dev_debug) thenif(self.smrt_showed_spot~=nil) thenlevel.map_remove_object_spot(self.id, "alife_presentation_smart_"..self.sim_type.."_"..self.smrt_showed_spot)endlevel.map_add_object_spot(self.id, "alife_presentation_smart_"..self.sim_type.."_"..spot, self:get_smart_props())self.smrt_showed_spot = spotelseif(self.smrt_showed_spot~=nil) and(level.map_has_object_spot(self.id, "alife_presentation_smart_"..self.sim_type.."_"..self.smrt_showed_spot)~=0)thenlevel.map_remove_object_spot(self.id, "alife_presentation_smart_base_"..self.smrt_showed_spot)endendend--' Обновление информации о смарте на игровом полеfunction se_smart_terrain:refresh()self:show()end--' Убирание отрисовки смарта на игровом полеfunction se_smart_terrain:hide()if self.smrt_showed_spot == nil thenreturnendlevel.map_remove_object_spot(self.id, "alife_presentation_smart_"..self.sim_type.."_"..self.smrt_showed_spot)endlocal function is_only_monsters_on_jobs(npc_info)for k,v in pairs (npc_info) doif v.is_monster == false thenreturn falseendendreturn trueend-- Обновление.-- В онлайне вызывается через binder.-- Также может вызваться принудительно из xr_effectsfunction se_smart_terrain:update()cse_alife_smart_zone.update( self )if dev_debug thenself:refresh() -- Не забыть потом заремитьendlocal current_time = time_global()if simulation_objects.is_on_the_same_level(self, alife():actor()) thenlocal dist_to_actor = self.position:distance_to(alife():actor().position)local old_dist_to_actor = (nearest_to_actor_smart.id == nil and nearest_to_actor_smart.dist) or alife():object(nearest_to_actor_smart.id).position:distance_to(alife():actor().position)if dist_to_actor < old_dist_to_actor thennearest_to_actor_smart.id = self.idnearest_to_actor_smart.dist = dist_to_actorendend-- Апдейт респауна отрядов симуляции.if self.respawn_params ~= nil thenself:try_respawn()endif self.check_time~=nil and current_time < self.check_time thenreturnend--проверить есть ли кто-то в смарте, если есть и костры не включены то включить,--еще проверить есть ли актер, чтоб была гарантия что костры проспонились...if is_only_monsters_on_jobs(self.npc_info) and self.campfires_on thenbind_campfire.turn_off_campfires_by_smart_name(self:name())self.campfires_on = falseelseif not is_only_monsters_on_jobs(self.npc_info) and not self.campfires_on thenbind_campfire.turn_on_campfires_by_smart_name(self:name())self.campfires_on = trueendif db.actor ~= nil thenlocal distance = db.actor:position():distance_to_sqr(self.position)local idle_time = math.max(60, 0.003 * distance)self.check_time = current_time + idle_timeelseself.check_time = current_time + 10end-- Проверяем, не истек ли запрет на занимание работы, на которой убили НПСlocal current_time = game.get_game_time()for k,v in pairs(self.dead_time) doif current_time:diffSec(v) >= DEATH_IDLE_TIME thenself.dead_time[k] = nilendend-- Перевыбор работself:update_jobs()-- Апдейтим контрол реакции базы на игрокаif self.base_on_actor_control ~= nil thenself.base_on_actor_control:update()end-- Апдейт доступности для симуляции.simulation_objects.get_sim_obj_registry():update_avaliability(self)end-- Переведение смарта в напряженное состояниеfunction se_smart_terrain:set_alarm()self.smart_alarm_time = game.get_game_time()end-- Проверяет. а не прошел ли аларм в смартеfunction se_smart_terrain:check_alarm()if self.smart_alarm_time == nil thenreturnendif game.get_game_time():diffSec(self.smart_alarm_time) > 21600 then -- 6 Игровых часовself.smart_alarm_time = nilendend-- установить логику и сообщить смарту, что объект перешёл в онлайн.-- вызывается из net_spawn() объектовfunction setup_gulag_and_logic_on_spawn(obj, st, sobject, stype, loaded)local sim = alife()local sobject = alife():object(obj:id())if sim ~= nil and sobject thenlocal strn_id = sobject.m_smart_terrain_idprintf( "setup_gulag_and_logic_on_spawn obj=%s, strn_id=%s, loaded=%s", obj:name(), tostring(strn_id), tostring(loaded))if strn_id ~= nil and strn_id ~= 65535 thenlocal strn = sim:object(strn_id)local need_setup_logic = (not loaded) and (strn.npc_info[obj:id()] and strn.npc_info[obj:id()].begin_job == true)if need_setup_logic thenstrn:setup_logic(obj)elsexr_logic.initialize_obj(obj, st, loaded, db.actor, stype)endelsexr_logic.initialize_obj(obj, st, loaded, db.actor, stype)endelsexr_logic.initialize_obj(obj, st, loaded, db.actor, stype)endend-- Убираем объект из смарта при смертиfunction on_death(obj)local sim = alife()if sim thenlocal obj = sim:object(obj.id)if obj == nil then return endlocal strn_id = obj:smart_terrain_id()if strn_id ~= 65535 thenprintf("clear dead object %s", obj:name())sim:object(strn_id):clear_dead(obj)endendend--***********************************************************************************************--* SIMULATION_TARGET_SMART *--***********************************************************************************************-- Получить позицию, левел вертекс, гейм вертекс обьекта.function se_smart_terrain:get_location()return self.position, self.m_level_vertex_id, self.m_game_vertex_idend-- Достигнут ли я отрядом выбравшим меня как цель.function se_smart_terrain:am_i_reached(squad)local squad_pos, squad_lv_id, squad_gv_id = squad:get_location()local target_pos, target_lv_id, target_gv_id = self:get_location()if game_graph():vertex(squad_gv_id):level_id() ~= game_graph():vertex(target_gv_id):level_id() thenreturn falseendif IsMonster(alife():object(squad:commander_id())) and squad:get_script_target() == nil thenreturn squad_pos:distance_to_sqr(target_pos) <= 25endreturn squad.always_arrived or squad_pos:distance_to_sqr(target_pos) <= self.arrive_dist^2end-- Вызывается 1 раз после достижения меня отрядом выбравшим меня как цель.function se_smart_terrain:on_after_reach(squad)for k in squad:squad_members() dolocal obj = k.objectsquad.board:setup_squad_and_group(obj)endsquad.current_target_id = self.idend-- Вызывается 1 раз в момент выбора меня как цели.function se_smart_terrain:on_reach_target(squad)-- squad.sound_manager:set_storyteller(squad:commander_id())-- squad.sound_manager:set_story("squad_begin_attack")squad:set_location_types(self:name())self.board:assign_squad_to_smart(squad, self.id)for k in squad:squad_members() doif db.offline_objects[k.id] ~= nil thendb.offline_objects[k.id] = {}endend-- self.board:exit_smart(squad, squad.smart_id)end-- Возвращает CALifeSmartTerrainTask на меня, вызывается из smart_terrain:task()function se_smart_terrain:get_alife_task()return self.smart_alife_taskendfunction smart_terrain_squad_count(board_smart_squads)local count = 0for k,v in pairs(board_smart_squads) doif v:get_script_target() == nil thencount = count + 1endendreturn countendfunction se_smart_terrain:sim_available()if self.base_on_actor_control ~= nil and self.base_on_actor_control.status ~= smart_terrain_control.NORMAL thenreturn falseendreturn trueendlocal is_squad_monster ={["monster_predatory_day"] = true,["monster_predatory_night"] = true,["monster_vegetarian"] = true,["monster_zombied_day"] = true,["monster_zombied_night"] = true,["monster_special"] = true}function surge_stats()local sim_obj_registry = simulation_objects.get_sim_obj_registry().objectslocal sim_squads = {["zaton"] = {},["jupiter"] = {},["pripyat"] = {},["escape"] = {}}local sim_smarts = {["zaton"] = {},["jupiter"] = {},["pripyat"] = {},["escape"] = {}}for k,v in pairs(sim_obj_registry) doif v:clsid() == clsid.smart_terrain and tonumber(v.props["surge"]) > 0 thenlocal level_name = alife():level_name(game_graph():vertex(v.m_game_vertex_id):level_id())if sim_smarts[level_name] ~= nil thentable.insert(sim_smarts[level_name], v)endendif v:clsid() == clsid.online_offline_group_s thenlocal squad_params = sim_board.simulation_activities[v.player_id]if squad_params ~= nil thenlocal smart_params = squad_params.smart.surgeif smart_params ~= nil thenlocal level_name = alife():level_name(game_graph():vertex(v.m_game_vertex_id):level_id())if sim_squads[level_name] ~= nil thentable.insert(sim_squads[level_name], v)endendendendendlocal function print_smarts_and_squads_by_level(level_name)printf("LEVEL: [%s]", level_name)local max_capacity_total = 0for i = 1, #sim_smarts[level_name] dolocal smart = sim_smarts[level_name]max_capacity_total = max_capacity_total + smart.max_populationlocal squad_count = smart_terrain_squad_count(sim_board.get_sim_board().smarts[smart.id].squads)printf("smart: [%s] max_population [%d] squad_count [%d]", smart:name(),smart.max_population, squad_count)endprintf("TOTAL: capacity total : [%d] squads total [%d]" , max_capacity_total, #sim_squads[level_name])endprint_smarts_and_squads_by_level("zaton")print_smarts_and_squads_by_level("jupiter")print_smarts_and_squads_by_level("pripyat")print_smarts_and_squads_by_level("escape")end-- Мой прекондишн.function se_smart_terrain:target_precondition(squad, need_to_dec_population)if self.respawn_only_smart == true thenreturn falseendlocal squad_count = smart_terrain_squad_count(self.board.smarts[self.id].squads)if need_to_dec_population thensquad_count = squad_count - 1endif squad_count ~= nil and (self.max_population <= squad_count) then--printf("smart terrain [%s] precondition returns false for squad [%s]", self:name(), squad:name())-- if tonumber(self.props["surge"]) > 0 and xr_conditions.surge_started() then-- printf("SURGE_SMART_STATS : smart [%s]\n max_population = %d \ squad_count = %d", self:name(), self.max_population, squad_count)-- endreturn falseendlocal squad_params = sim_board.simulation_activities[squad.player_id]if squad_params == nil or squad_params.smart == nil then--printf("smart terrain [%s] precondition returns false for squad [%s]", self:name(), squad:name())return falseendif tonumber(self.props["resource"] )> 0 thenlocal smart_params = squad_params.smart.resourceif smart_params ~= nil and smart_params.prec(squad, self) thenreturn trueendendif tonumber(self.props["base"] )> 0 thenlocal smart_params = squad_params.smart.baseif smart_params ~= nil and smart_params.prec(squad, self) thenreturn trueendendif tonumber(self.props["lair"] )> 0 thenlocal smart_params = squad_params.smart.lairif smart_params ~= nil and smart_params.prec(squad, self) thenreturn trueendendif tonumber(self.props["territory"] )> 0 thenlocal smart_params = squad_params.smart.territoryif smart_params ~= nil and smart_params.prec(squad, self) thenreturn trueendendif tonumber(self.props["surge"] )> 0 thenlocal smart_params = squad_params.smart.surgeif smart_params ~= nil and smart_params.prec(squad, self) thenreturn trueendend--printf("smart terrain [%s] precondition returns false for squad [%s]", self:name(), squad:name())return false--[[local squad_count = smart_terrain_squad_count(self.board.smarts[self.id].squads)if squad_count ~= nil and (self.max_population <= squad_count) then return false endif squad.player_id == "stalker" and in_time_interval(9,19) and tonumber(self.props["resource"] )> 0 thenreturn trueend--if squad.player_id ~= "monster_predatory" and squad.player_id ~= "monster_vegetarian" thenif not is_squad_monster[squad.player_id] thenif tonumber(self.props["base"]) > 0 and in_time_interval(20,8) thenreturn trueendif tonumber(self.props["base"] ) > 0 and xr_conditions.surge_started() thenreturn trueendelseif tonumber(self.props["lair"] ) > 0 and xr_conditions.surge_started() thenreturn trueendif tonumber(self.props["lair"] ) > 0 and in_time_interval(7,20) thenreturn trueendendreturn false]]end-- Посчитать мой приоритет для отряда.function se_smart_terrain:evaluate_prior(squad)return simulation_objects.evaluate_prior(self, squad)end-- Респаун симуляции.function se_smart_terrain:check_respawn_params(respawn_params)--printf("CHECK RESPAWN PARAMS %s", self:name())self.respawn_params = {}self.already_spawned = {}self.respawn_point = trueif not self.ini:section_exist(respawn_params) thenabort("Wrong smatr_terrain respawn_params section [%s](there is no section)", respawn_params)endlocal n = self.ini:line_count(respawn_params)if n == 0 thenabort("Wrong smatr_terrain respawn_params section [%s](empty params)", respawn_params)endfor j=0,n-1 dolocal result, prop_name, prop_condlist = self.ini:r_line(respawn_params,j,"","")if not self.ini:section_exist(prop_name) thenabort("Wrong smatr_terrain respawn_params section [%s] prop [%s](there is no section)", respawn_params, prop_name)endlocal spawn_squads = utils.cfg_get_string(self.ini, prop_name, "spawn_squads", self, false, "", nil)local spawn_num = utils.cfg_get_string(self.ini, prop_name, "spawn_num", self, false, "", nil)if spawn_squads == nil thenabort("Wrong smatr_terrain respawn_params section [%s] prop [%s] line [spawn_squads](there is no line)", respawn_params, prop_name)elseif spawn_num == nil thenabort("Wrong smatr_terrain respawn_params section [%s] prop [%s] line [spawn_num](there is no line)", respawn_params, prop_name)endspawn_squads = utils.parse_names(spawn_squads)spawn_num = xr_logic.parse_condlist(nil, prop_name, "spawn_num", spawn_num)self.respawn_params[prop_name] = {}self.already_spawned[prop_name] = {}self.respawn_params[prop_name].squads = spawn_squadsself.respawn_params[prop_name].num = spawn_numself.already_spawned[prop_name].num = 0endendfunction se_smart_terrain:call_respawn()local available_sects = {}printf("respawn called from smart_terrain [%s]", self:name())for k,v in pairs(self.respawn_params) doif tonumber(xr_logic.pick_section_from_condlist(db.actor, nil,v.num)) > self.already_spawned[k].num thentable.insert(available_sects,k)endendif #available_sects > 0 thenlocal sect_to_spawn = available_sects[math.random(1,#available_sects)]local sect_to_spawn_params = self.respawn_params[sect_to_spawn]local squad = sect_to_spawn_params.squads[math.random(1,#sect_to_spawn_params.squads)]squad = self.board:create_squad(self, squad)squad.respawn_point_id = self.idsquad.respawn_point_prop_section = sect_to_spawnself.board:enter_smart(squad, self.id)for m in squad:squad_members() doself.board:setup_squad_and_group(m.object)endself.already_spawned[sect_to_spawn].num = self.already_spawned[sect_to_spawn].num + 1endendfunction se_smart_terrain:try_respawn()--printf("TRY RESPAWN %s", self:name())local curr_time = game.get_game_time()if self.last_respawn_update == nil or curr_time:diffSec(self.last_respawn_update) > RESPAWN_IDLE thenself.last_respawn_update = curr_timeif self.sim_avail ~= nil and xr_logic.pick_section_from_condlist(db.actor or alife():actor(), self, self.sim_avail) ~= "true" then return endlocal squad_count = smart_terrain_squad_count(self.board.smarts[self.id].squads)if self.max_population <= squad_count then printf("%s cannot respawn due to squad_count %s of %s", self:name(), self.max_population, squad_count) return endlocal dist_to_actor = alife():actor().position:distance_to_sqr(self.position)if dist_to_actor < RESPAWN_RADIUS^2 then printf("%s cannot respawn due to distance", self:name()) return endself:call_respawn()endend ---------------------------------------------------------------------------------- Surge manager class ----------------------------------------------------------- Made by Peacemaker ------------------------------------------------------------ 05.03.07 ----------------------------------------------------------------------------------------------------------------------------------------------------local surge_manager = nillocal surge_shock_pp_eff = 1local earthquake_cam_eff = 2local sleep_cam_eff = 3local sleep_fade_pp_eff = 4local START_MIN_SURGE_TIME = 2*60*60local START_MAX_SURGE_TIME = 4*60*60local MIN_SURGE_TIME = 12*60*60local MAX_SURGE_TIME = 24*60*60local prev_sec = 0local immuned_to_surge_squads = {["monster_predatory_day"] = true,["monster_predatory_night"] = true,["monster_vegetarian"] = true,["monster_zombied_day"] = true,["monster_zombied_night"] = true,["monster_special"] = true,["monster"] = true,["zombied"] = true}class "CSurgeManager"function CSurgeManager:__init()endfunction CSurgeManager:initialize()self.ini = ini_file("misc\\surge_manager.ltx")self.levels_respawn = {zaton = false, jupiter = false, pripyat = false, escape = false}self.started = falseself.finished = trueself.time_forwarded = falseself.skip_message = falseself.task_given = falseself.effector_set = falseself.second_message_given = falseself.ui_disabled = falseself.blowout_sound = falseself.surge_time = 190self.inited_time = game.CTime()self.last_surge_time = game.get_game_time()self._delta = math.random(START_MIN_SURGE_TIME, START_MAX_SURGE_TIME) -- global minutes, время между выбросамиself.count = 0self.covers = {}self.condlist = {}self.survive = {}local ini = self.inilocal cond_string = "true"if(ini:line_exist("settings", "condlist")) thencond_string = ini:r_string("settings", "condlist")endself.condlist = xr_logic.parse_condlist(nil, "surge_manager", "condlist", cond_string)cond_string = "false"if(ini:line_exist("settings", "survive")) thencond_string = ini:r_string("settings", "survive")endself.survive = xr_logic.parse_condlist(nil, "surge_manager", "survive_condlist", cond_string)self:init_surge_covers()self.surge_message = ""self.surge_task_sect = ""self.loaded = falseendfunction CSurgeManager:init_surge_covers()local ini = self.inifor i = 0, ini:line_count("list")-1 dotemp1, id, temp2 = ini:r_line("list", i, "", "")local zone = db.zone_by_name[id]if zone ~= nil thenself.count = self.count + 1self.covers[self.count] = zoneif(ini:line_exist(id, "condlist")) thenself.covers[self.count].condlist = {}self.covers[self.count].condlist = xr_logic.parse_condlist(npc, id, "condlist", ini:r_string(id, "condlist"))endendendendfunction CSurgeManager:get_nearest_cover()if(self.loaded) thenself:init_surge_covers()endlocal hides = {}utils.copy_table(hides, self.covers)if(self.count>0) thenfor k,v in pairs(hides) doif (v.condlist) thenlocal sect = xr_logic.pick_section_from_condlist(db.actor, nil, v.condlist)if(sect~="true" and sect~=nil) thentable.remove(hides, k)endendendlocal nearest_cover_id = hides[1]:id()local nearest_cover_dist = hides[1]:position():distance_to(db.actor:position())for k,v in pairs(hides) doif db.storage[v:id()].object:inside(db.actor:position()) thenreturn v:id()endlocal dist = v:position():distance_to(db.actor:position())if(dist if(v.condlist) thenlocal sect = xr_logic.pick_section_from_condlist(db.actor, nil, v.condlist)if(sect=="true") thennearest_cover_id = v:id()nearest_cover_dist = distendelsenearest_cover_id = v:id()nearest_cover_dist = distendendendif(nearest_cover_id==hides[1]:id()) thenif(hides[1].condlist) thenlocal sect = xr_logic.pick_section_from_condlist(db.actor, nil, hides[1].condlist)if(sect~="true" and sect~=nil) thenreturn nilendendendreturn nearest_cover_idelsereturn nilendendfunction CSurgeManager:update()if(device().precache_frame > 1) thenreturnendif not(self.started) thenlocal g_time = game.get_game_time()if(self.time_forwarded) thenlog("--->delta="..tostring(self._delta))log("--->diffSec="..tostring(g_time:diffSec(self.last_surge_time)))local diff = math.abs(self._delta - g_time:diffSec(self.last_surge_time))log("--->diff="..tostring(diff))if(diff<3600) thenself._delta = 3*3600+g_time:diffSec(self.last_surge_time)endself.time_forwarded = falseendif(g_time:diffSec(self.last_surge_time) < self._delta) thenreturnendif(xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, self.condlist) ~= "true") thenreturnendif not(self:get_nearest_cover()) thenreturnendself:start()returnend-------------------------------------------------------------------- update herelocal diff_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/level.get_time_factor())if(prev_sec~=diff_sec) thenprev_sec = diff_seclog("------>diff_sec="..tostring(diff_sec))local cover = self:get_nearest_cover()if(cover==nil and self.count==0) thenself:init_surge_covers()returnendlocal level_name = level.name()if(level_name=="labx8" or level_name=="jupiter_underground") thenprintf("Surge stopped because of level!")self:end_surge()returnendif(diff_sec>=self.surge_time) thenif(level) thenif(level.name()=="zaton") thenxr_sound.set_sound_play(db.actor:id(), "zat_a2_stalker_barmen_after_surge")elseif(level.name()=="jupiter") thenxr_sound.set_sound_play(db.actor:id(), "jup_a6_stalker_medik_after_surge")elseif not has_alife_info("pri_b305_fifth_cam_end") thenxr_sound.set_sound_play(db.actor:id(), "pri_a17_kovalsky_after_surge")endendself:end_surge()elseif(self.loaded) thenif(self.blowout_sound)thenxr_sound.play_sound_looped(db.actor:id(), "blowout_rumble")endif(self.effector_set) thenlevel.add_pp_effector("surge_shock.ppe", surge_shock_pp_eff, true)endif(self.second_message_given) thenxr_sound.play_sound_looped(db.actor:id(), "surge_earthquake_sound_looped")level.add_cam_effector("camera_effects\\earthquake.anm", earthquake_cam_eff, true, "")endself.loaded = falseendself:launch_rockets()if(self.effector_set) thenlevel.set_pp_effector_factor(surge_shock_pp_eff, diff_sec/90, 0.1)endif(self.blowout_sound) thenxr_sound.set_volume_sound_looped(db.actor:id(), "blowout_rumble", diff_sec/180)endif(diff_sec>=140 and not(self.ui_disabled) and (cover==nil or not(db.storage[cover].object:inside(db.actor:position())))) thenlocal att = 1-(185-diff_sec)/(185-140)att = att*att*att*0.3local h = hit()h.type = hit.telepatich.power = atth.impulse = 0.0h.direction = vector():set(0,0,1)h.draftsman = db.actorif(xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, self.survive)=="true") thenif(db.actor.health<=h.power) thenh.power = db.actor.health - 0.05if(h.power<0) thenh.power = 0endendenddb.actor:hit(h)endif(diff_sec>=185) and not(self.ui_disabled) thenself:kill_all_unhided()self.ui_disabled = trueelseif(diff_sec>=140) and not(self.second_message_given) thenif(level) thenif(level.name()=="zaton") thenxr_sound.set_sound_play(db.actor:id(), "zat_a2_stalker_barmen_surge_phase_2")elseif(level.name()=="jupiter") thenxr_sound.set_sound_play(db.actor:id(), "jup_a6_stalker_medik_phase_2")elseif not has_alife_info("pri_b305_fifth_cam_end") thenxr_sound.set_sound_play(db.actor:id(), "pri_a17_kovalsky_surge_phase_2")endendxr_sound.play_sound_looped(db.actor:id(), "surge_earthquake_sound_looped")level.add_cam_effector("camera_effects\\earthquake.anm", earthquake_cam_eff, true, "")self.second_message_given = trueelseif(diff_sec>=100) and not(self.effector_set) thenlevel.add_pp_effector("surge_shock.ppe", surge_shock_pp_eff, true)-- level.set_pp_effector_factor(surge_shock_pp_eff, 0, 10)self.effector_set = trueelseif(diff_sec>=35) and not(self.blowout_sound)thenxr_sound.set_sound_play(db.actor:id(), "blowout_begin")xr_sound.play_sound_looped(db.actor:id(), "blowout_rumble")xr_sound.set_volume_sound_looped(db.actor:id(), "blowout_rumble", 0.25)self.blowout_sound = trueelseif(diff_sec>=0) and not(self.task_given)thenif(level) thenif(level.name()=="zaton") thenxr_sound.set_sound_play(db.actor:id(), "zat_a2_stalker_barmen_surge_phase_1")elseif(level.name()=="jupiter") thenxr_sound.set_sound_play(db.actor:id(), "jup_a6_stalker_medik_phase_1")elseif not has_alife_info("pri_b305_fifth_cam_end") thenxr_sound.set_sound_play(db.actor:id(), "pri_a17_kovalsky_surge_phase_1")endendlevel.set_weather_fx("fx_surge_day_3")self:give_surge_hide_task()self.task_given = trueendendendendfunction CSurgeManager:start(manual)local Y, M, D, h, m, s, ms = 0, 0, 0, 0, 0, 0, 0Y, M, D, h, m, s, ms = self.last_surge_time:get(Y, M, D, h, m, s, ms)if(manual) thenself.inited_time = game.get_game_time()elseself.inited_time:set(Y, M, D, h, m, s + self._delta, ms)enddiff_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/level.get_time_factor())log("--->start diff_sec="..tostring(diff_sec))local level_name = level.name()if(level_name=="labx8" or level_name=="jupiter_underground") thenprintf("Surge skipped because of level!")self.skip_message = trueself:skip_surge()returnendif(diff_sec+6>self.surge_time)thenprintf("Surge skipped while time forwarding!")self:skip_surge()elseself.started = trueself.finished = false-- autosaveif not has_alife_info("pri_b305_fifth_cam_end") or has_alife_info("pri_a28_actor_in_zone_stay") thenxr_effects.scenario_autosave(nil,nil,{"st_save_uni_surge_start"})endendendfunction CSurgeManager:skip_surge()local Y, M, D, h, m, s, ms = 0, 0, 0, 0, 0, 0, 0Y, M, D, h, m, s, ms = self.inited_time:get(Y, M, D, h, m, s, ms)self.last_surge_time:set(Y, M, D, h, m, s + self.surge_time, ms)self.started = falseself.finished = trueself.levels_respawn = {zaton = true, jupiter = true, pripyat = true, escape = true}self._delta = math.random(MIN_SURGE_TIME, MAX_SURGE_TIME)self.surge_message = ""self.surge_task_sect = ""self.task_given = falseself.effector_set = falseself.second_message_given = falseself.ui_disabled = falseself.blowout_sound = falseprev_sec = 0self:respawn_artefacts_and_replace_anomaly_zone()xr_statistic.inc_surges_counter()if (not self.skip_message) thennews_manager.send_tip(db.actor, "st_surge_while_asleep", nil, "recent_surge", nil, nil)self.skip_message = trueendendfunction CSurgeManager:end_surge(manual)self.started = falseself.finished = trueself.levels_respawn = {zaton = true, jupiter = true, pripyat = true, escape = true}self.last_surge_time = game.get_game_time()self._delta = math.random(MIN_SURGE_TIME, MAX_SURGE_TIME)self.surge_message = ""self.surge_task_sect = ""self.task_given = falseif(self.effector_set) thenxr_sound.stop_sound_looped(db.actor:id(), "blowout_rumble")endif(self.second_message_given) thenxr_sound.stop_sound_looped(db.actor:id(), "surge_earthquake_sound_looped")endlevel.remove_pp_effector(surge_shock_pp_eff)level.remove_cam_effector(earthquake_cam_eff)if(manual or (self.time_forwarded and level_weathers.get_weather_manager().weather_fx)) thenlevel.stop_weather_fx()-- level_weathers.get_weather_manager():select_weather(true)level_weathers.get_weather_manager():forced_weather_change()endself.effector_set = falseself.second_message_given = falseself.ui_disabled = falseself.blowout_sound = falseprev_sec = 0for k,v in pairs(db.signal_light) dov:stop_light()v:stop()endif self.loaded thenself:kill_all_unhided()endself:respawn_artefacts_and_replace_anomaly_zone()xr_statistic.inc_surges_counter()endfunction CSurgeManager:respawn_artefacts_and_replace_anomaly_zone()local lvl_nm = level.name()if(self.levels_respawn[lvl_nm]) thenself.levels_respawn[lvl_nm] = falseendlocal anomalies = db.anomaly_by_namefor k,v in pairs(anomalies) dov:respawn_artefacts_and_replace_anomaly_zone()--printf("respawn artefacts in anomal zone [%s]", tostring(k))endpda.change_anomalies_names()endfunction CSurgeManager:give_surge_hide_task()if(self.surge_message~="empty") thenlocal mess = ""if(self.surge_message=="") thenlocal time = 0mess = game.translate_string("hide_from_surge_message")elsemess = game.translate_string(self.surge_message)endendif(self.surge_task_sect~="empty") thenif(self.surge_task_sect=="") thentask_manager.get_task_manager():give_task("hide_from_surge")elsetask_manager.get_task_manager():give_task(self.surge_task_sect)endendendfunction get_squad_members(squad_id)local npcs_tbl = {}local squad = alife():object(squad_id)if(squad) thenfor obj in squad:squad_members() donpcs_tbl[obj.id] = trueendendreturn npcs_tblendfunction check_squad_level(squad_id)local squad = alife():object(squad_id)if(squad) thenlocal squad_level = alife():level_name(game_graph():vertex(squad.m_game_vertex_id):level_id())if(squad_level==level.name()) thenreturn trueendendreturn false -- can't delete squad on other levelendfunction check_squad_community_and_story_id(squad_id)local squad = alife():object(squad_id)if(squad) thenif(immuned_to_surge_squads[squad.player_id]) thenreturn false -- can't delete squad immune to surgeendif(get_object_story_id(squad.id)) thenreturn false -- can't delete squad with story idendendreturn trueendfunction check_squad_community(squad_id)local squad = alife():object(squad_id)if(squad) thenif(immuned_to_surge_squads[squad.player_id]) thenreturn false -- can't delete squad immune to surgeendendreturn trueendfunction check_squad_smart_props(squad_id)local squad = alife():object(squad_id)if(squad) thenlocal board = sim_board.get_sim_board()if(board and squad.smart_id and board.smarts[squad.smart_id]) thenlocal smart = board.smarts[squad.smart_id].smrtif(tonumber(smart.props["surge"])<=0) thenreturn trueendendendreturn false -- can't delete squad in his smart if squad is in coverendfunction CSurgeManager:kill_all_unhided()local h = hit()h.type = hit.fire_woundh.power = 0.9h.impulse = 0.0h.direction = vector():set(0,0,1)h.draftsman = db.actorfor k,v in pairs(bind_crow.crow_storage) dolocal obj = alife():object(v)if obj thenlocal crow = level.object_by_id(obj.id)if(crow and crow:alive()) thencrow:hit(h)endendendlocal board = sim_board.get_sim_board()for k,v in pairs(board.squads) dolocal squad = vif(check_squad_level(squad.id)) thenif(check_squad_community_and_story_id(squad.id)) thenlocal squad_npcs = get_squad_members(squad.id)for kk,vv in pairs(squad_npcs) dolocal obj = alife():object(kk)if(obj and not(get_object_story_id(obj.id))) thenif(check_squad_smart_props(squad.id)) thenprintf("Releasing npc [%s] from squad [%s] because of surge!",obj:name(), squad:name())local cl_obj = level.object_by_id(obj.id)if cl_obj ~= nil thencl_obj:kill(cl_obj)elseobj:kill()endelselocal release = truefor i = 1,#self.covers dolocal sr = self.coversif(sr and sr:inside(obj.position)) thenrelease = falseendendif(release) thenprintf("Releasing npc [%s] from squad [%s] because of surge!",obj:name(), squad:name())local cl_obj = level.object_by_id(obj.id)if cl_obj ~= nil thencl_obj:kill(cl_obj)elseobj:kill()endendendendendendendendlocal cover = self:get_nearest_cover()if(db.actor and db.actor:alive()) thenif not(cover and db.storage[cover] and db.storage[cover].object:inside(db.actor:position())) thenif has_alife_info("anabiotic_in_process") thenlocal counter_name = "actor_marked_by_zone_cnt"local cnt_value = xr_logic.pstor_retrieve(db.actor, counter_name, 0)xr_logic.pstor_store(db.actor, counter_name, cnt_value + 1)end--[[local hud = get_hud()hud:HideActorMenu()hud:HidePdaMenu()db.actor:stop_talk()level.disable_input()level.hide_indicators_safe()db.actor:hide_weapon()]]--xr_effects.disable_ui_only(db.actor, nil)if(xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, self.survive)~="true") thenself:kill_all_unhided_after_actor_death()db.actor:kill(db.actor)returnelselevel.add_cam_effector("camera_effects\\surge_02.anm", sleep_cam_eff, false, "surge_manager.surge_callback")level.add_pp_effector("surge_fade.ppe", sleep_fade_pp_eff, false)db.actor.health = db.actor.health-0.05endendendendfunction CSurgeManager:kill_all_unhided_after_actor_death()local board = sim_board.get_sim_board()for k,v in pairs(board.squads) dolocal squad = vif(check_squad_level(squad.id)) thenif(check_squad_community(squad.id)) thenlocal squad_npcs = get_squad_members(squad.id)for kk,vv in pairs(squad_npcs) dolocal obj = alife():object(kk)if obj thenlocal release = truefor i = 1,#self.covers dolocal sr = self.coversif(sr and sr:inside(obj.position)) thenrelease = falseendendif(release) thenprintf("Releasing npc [%s] from squad [%s] after actors death because of surge!",obj:name(), squad:name())local cl_obj = level.object_by_id(obj.id)if cl_obj ~= nil thencl_obj:kill(cl_obj)elseobj:kill()endendendendendendendendfunction surge_callback()level.add_cam_effector("camera_effects\\surge_01.anm", sleep_cam_eff, false, "surge_manager.surge_callback2")-- level.stop_weather_fx()-- level.change_game_time(0,0,15)-- level_weathers.get_weather_manager():forced_weather_change()endfunction surge_callback2()xr_effects.enable_ui(db.actor, nil)--[[level.enable_input()level.show_indicators()db.actor:restore_weapon()]]--endfunction CSurgeManager:launch_rockets()for k,v in pairs(db.signal_light) doif not(v:is_flying()) thenv:launch()endendendfunction CSurgeManager:save(packet)set_save_marker(packet, "save", false, "SurgeHide")packet:w_bool(self.finished)packet:w_bool(self.started)utils.w_CTime(packet, self.last_surge_time)if(self.started) thenutils.w_CTime(packet, self.inited_time)packet:w_bool(self.levels_respawn.zaton)packet:w_bool(self.levels_respawn.jupiter)packet:w_bool(self.levels_respawn.pripyat)packet:w_bool(self.levels_respawn.escape)packet:w_bool(self.task_given)packet:w_bool(self.effector_set)packet:w_bool(self.second_message_given)packet:w_bool(self.ui_disabled)packet:w_bool(self.blowout_sound)packet:w_stringZ(self.surge_message)packet:w_stringZ(self.surge_task_sect)endpacket:w_u32(self._delta)set_save_marker(packet, "save", true, "SurgeHide")endfunction CSurgeManager:load(packet)set_save_marker(packet, "load", false, "SurgeHide")self:initialize()self.finished = packet:r_bool()self.started = packet:r_bool()self.last_surge_time = utils.r_CTime(packet)if(self.started) thenself.inited_time = utils.r_CTime(packet)self.levels_respawn.zaton = packet:r_bool()self.levels_respawn.jupiter = packet:r_bool()self.levels_respawn.pripyat = packet:r_bool()self.levels_respawn.escape = packet:r_bool()self.task_given = packet:r_bool()self.effector_set = packet:r_bool()self.second_message_given = packet:r_bool()self.ui_disabled = packet:r_bool()self.blowout_sound = packet:r_bool()self.surge_message = packet:r_stringZ()self.surge_task_sect = packet:r_stringZ()endself._delta = packet:r_u32()self.loaded = trueset_save_marker(packet, "load", true, "SurgeHide")end--------------------------------------------------------------------------------function get_surge_manager()if surge_manager == nil thensurge_manager = CSurgeManager()endreturn surge_managerendfunction start_surge(p)local m = get_surge_manager()if(m:get_nearest_cover()) thenm:start(true)elseprintf("Error: Surge covers are not set! Can't manually start")endendfunction actor_in_cover()local m = get_surge_manager()local cover_id = m:get_nearest_cover()if (cover_id ~= nil) and (db.storage[cover_id].object:inside(db.actor:position())) thenreturn trueelsereturn falseendendfunction stop_surge()local m = get_surge_manager()if(m.started) thenm:end_surge(true)endendfunction get_task_descr()local descr = ""if(actor_in_cover()) thendescr = game.translate_string("hide_from_surge_descr_2_a")elsedescr = game.translate_string("hide_from_surge_descr_1_a")endreturn descrendfunction get_task_target()local m = get_surge_manager()if(actor_in_cover()) thenreturn nilendreturn m:get_nearest_cover()endfunction set_surge_message(mess)local m = get_surge_manager()m.surge_message = messendfunction set_surge_task(task)local m = get_surge_manager()m.surge_task_sect = taskendfunction is_started()local m = get_surge_manager()return m.startedendfunction is_killing_all()local m = get_surge_manager()if(m.started and m.ui_disabled) thenreturn trueendreturn falseendfunction is_finished()local m = get_surge_manager()return m.finished == trueendfunction resurrect_skip_message()local m = get_surge_manager()m.skip_message = falseendfunction sound_started()local m = get_surge_manager()return m.started and m.blowout_soundend )> Все.Это все скрипты которые я трогал. Такие огромные тексты врядли кто прокручивать станет. Лучше заливай файлики на обменник и выкладывай ссылкой. Для менее огромных кодов, используй тег "код", дабы сохранять форматирование. И пиши без "хз". Cyclone Изменено 10 Мая 2013 пользователем Cyclone Ссылка на комментарий
Shredder 49 Опубликовано 10 Мая 2013 Поделиться Опубликовано 10 Мая 2013 В логе явно говориться, что на строке 1256 идёт сравнение числа с nil, смотрим строку 1256: if squad_count ~= nil and (self.max_population <= squad_count) then И тут невооружённым глазом видно, что nil-ом может быть только self.max_population. Следовательно, для какого-то из смартов он не указан. Ссылка на комментарий
dmitry-strelok 0 Опубликовано 10 Мая 2013 Поделиться Опубликовано 10 Мая 2013 А может из-за того,что у меня на локации несколько обычных смартов?Просто я их в заранее поставил но в конфигах не трогал. Пойду уберу их.Просто мне в прошлый раз сказали,что пустой смарт не влияет и вылета не должно быть. Ссылка на комментарий
stalker_bes 0 Опубликовано 10 Мая 2013 Поделиться Опубликовано 10 Мая 2013 (изменено) Если в пустых smart_terrain есть ссылка на script\"твоя локация"\smart, а там не прописано максимальная пуполяция на них то вполне возможно вылет из-за этого. Изменено 10 Мая 2013 пользователем stalker_bes Ссылка на комментарий
dmitry-strelok 0 Опубликовано 10 Мая 2013 Поделиться Опубликовано 10 Мая 2013 Нет,они просто пустые. Убрал смарты лишние,те которые пустые были,вообщем все работает!Они идут по свободным смартам)Спасибо огромное,что хоть подсказку дали про пустышки! Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти