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

proper70

Жители
  • Число публикаций

    89
  • Регистрация

  • Последнее посещение

О proper70

  • День рождения 09.01.1970

Контакты

  • Сайт
    http://
  • ICQ
    0

Информация

  • Реальное имя
    Владимир
  • Город
    Новосибирск

Недавние посетители профиля

5 669 просмотров профиля
  1. Инструментарий для мододелов

    Всем привет! Подскажите что может быть: плагин для ТС вдруг перестал читать DBшки. Архиваторный работает а вот explorer - вдруг перестал. Ничего не переустанавливал не делал не правил. На ноуте - все работает, а на основном компе - перестало. Видно что читает, пауза есть, а потом пустой список. Все фильтры отключены, все очевидные вещи проверил. В чем может быть дело? win 7 TC 8.01 Все, разобрался) файл thumbs.db затесался в папку с игрой) еще и скрытый, зараза) Удалил и все прошло)
  2. Справочник по функциям и классам

    Несколько раз порывался написать этот пост, да все откладывал. Наконец нашел время. Хотя глобальное модостроение и пришло в свою завершающую фазу, но все же, напишу то, что считаю нужным, может вдруг кому и пригодится. Речь пойдет об оптимальных со всех точек зрения и построенных на правилах объектно ориентированного программирования конструкциях, как я их вижу (уверен, далеко не самый лучший вариант, но все же), которые должны были бы быть в скриптах сталкера, но которых увы, нет. Предлагаемый мной вариант организации кода позволил бы очень сильно уменьшить размер конфигов и скриптов, а также достаточно ощутимо оптимизировал бы их использование и выполнение. Жаль, что это все я понял только тогда, когда ОП-2 уже был готов и зарелизен) Можно было бы сэкономить кучу времени и нервов, отлаживая и доводя до ума все это) Да и переделывать уже имеющееся никто не будет, но эта инфа вполне может пригодиться в будущих скриптах. Начнем с класса ini_file - чтения конфигов. Огромная проблема в том, что он вылетает при каждой попытке прочесть отсутстувующую секцию или параметр. И чтобы решить эту проблему, многие мододелы, начиная с ПЫСов, нагородили разных оберток - функций, которые закрывают этот вылет, но при этом очень усложняют собственно сам процесс чтения. Тут не нужно было не городить всякие "примочки" "обертки" "проверки" и прочее, а просто сделать, например, вот так: class script_ini (ini_file) function r_string(section, line) if ini_file.section_exist(self, section) and ini_file.line_exist(self, section, line) then return ini_file.r_string(self, section, line) else return "" end end И т.д. переопределить все функции, прописав в них возврат значения по умолчанию при отсутствии секции либо параметра, и все дальнейшие скрипты строить исходя из этого. И тогда не нужно было плодить всяких utils.cfg_get_string в логике, и тот ужас, который мы имеем в Солянке в виде getIniValueString. Достаточно было в _G.script написать вот это: ini = script_ini(system_ini()) И далее, во всех скриптах писать просто: local var = ini:r_string(section, line) if var == нужное значение then И все. Никаких вылетов при отсутствии секции или параметра не будет. Конечно, при правильной организации кода эти фишки должны были быть встроены в оригинал класса ini_file изначально, но раз их нет, то их надо было просто добавить скриптово) Также, для удобочитаемости и удобоиспользования: вместо treasure_manager.get_treasure_manager():give_treasure("mil_borov_secret") написать в опять же в _G.script: treasure = treasure_manager.CTreasure() И в любых вызовах использовать treasure:give("mil_borov_secret") Соответсвенно сократив имена методов класса. Ведь этот класс все равно создается единожды при лоаде и хранится в памяти всю игру. Аналогично поступить для всех глобальных классов. Следующее. Просто напрашивается всеми фибрами души вместо amk.start_timer сделать опять же в _G: timer = amk.CTimer(name, delay, parameters) B далее у этого класса методы start, g_start, has, stop, execute (при наступлении времени) и любые другие. И, наконец, самое нужное, на мой взгляд, и самое опитимизирующее практически все скрипты изменение: class CLogic И в нем методы: net_spawn (аналог set_scheme+assign_storage_and_bind+subscribe_action_for_events), update (аналог pick_section_from_condlist+try_switch_to_another_section - все апдейты), net_destroy (аналог deactivate+reset_scheme подключенных схем) Далее, переопределяем object_binder: class "script_object_binder" (object_binder) function script_object_binder:__init(obj) super(obj) self.object.logic = CLogic() -- здесь можно добавить проверки, есть ли логика у объекта, и при каких условиях ее надо подключать. end function script_object_binder:net_spawn(data) object_binder.net_spawn(self, data) self.object.logic:net_spawn() end function script_object_binder:update(delta) object_binder.update(self, delta) self.object.logic:update(delta) end function script_object_binder:net_destroy() object_binder.net_destroy(self) self.object.logic:net_destroy() end И т.д. И затем глобализируем этот переопределенный класс в _G: object_binder = script_object_binder() И тогда в биндерах объектов ничего править не нужно - все само переопределится - логика всегда будет подключаться полностью автоматически. Просто идеальный вариант, но увы, с логикой имеем только то, что имеем)) Движок при каждом старте выполняет команду ini_file("system.ini"). то есть он вычитывает и строит в памяти всю таблицу подключенных секций и параметров. Ссылка на эту таблицу возвращается функцией system_ini(). Причем все секции и параметры упорядочены по алфавиту (это лекго увидеть, выведя в лог список параметров любой секции через r_line), и, судя по всему, проиндексированы, так как получение любого параметра происходит очень быстро (можете сами проверить, запустив цикл на миллион чтений и замерив время выполнения). Другими словами - к файлу на диске движок при чтении прараметра из конфига никак не обращается - все читается один раз при старте. Следовательно, всякие дублирования данных из конфигов в таблицах, а также предубеждения, что system_ini() нельзя читать на апдейте, ибо это тормоз - абсолютно неверны. Наоборот, не только можно, но и даже нужно использовать чтение напрямую из конфигов вместо создания дублирующих таблиц. Конечно, при условии определения разовой, глобальной переменной, описаной выше: ini = system_ini() А не в каждом скрипте создавать свою копию. Исходя из вышеизложенного, наиболее оптимальный вариант работы с конфигами будет примерно следующим. Покажу на примере task_manager.CRandomTask:__init(). В ней достаточно прочитать в локальные таблицы и хранить в памяти постоянно только вот это: curr_task_info.type = self.task_ini:r_string(id, "type") curr_task_info.name = id А все остальное вычитывать на лету при активации диалога с вендором. Тогда в памяти будут храниться только реально нужные данные, по которым ведется поиск и отбор. А всё остальное - значения секций - можно прочесть "на лету". Это исключает дублирование данных движком и скриптами. Простой пример. Все монстры имеют общий базовый конфиг monster_base: [m_burer_e]:monster_base Так вот, если в конфиге monster_base добавить параметр monster = true Вот так: [monster_base]:common_ph_friction_params_on_npc_death actor_hit_effect = effector_monster_hit monster = true то тогда таблица IAmAMonster[obj:clsid()] - становится абсолютно ненужной. Вместо нее пишем: function IAmAMonster(section) return ini:line_exist(section, "monster") end Все. Никаких таблиц. Причем, если сделать секции stalker_base, ammo_base, wpn_base, artefact_base, medkit_base, detector_base, food_base, outfit_base и т.д., и задать там аналогичный параметр, то все эти таблицы также станут ненужными. Скажете - IAmAMonster - не такая уж и большая таблица. А как быть тогда с соляночными таблицами в protected_items? Также с различными списками в amk_mod.anom_recept_komp, news_data.ommunity_name, monster_classes, weapon_classes, различными templates, art_hit.art_hit, scient, death_manager.data_by_community xrs_armor.excluded_npcs и с многими другими таблицами? Ведь для того, чтобы сделать, чтобы item был protected, достаточно создать секцию [protected_item] protected_item = true И прописывать ее в наследование в каждую секцию, которую надо защитить: [bandranen_pda]:identity_immunities, protected_item И все - и тогда простая проверка ini:section_exist(section, "protected_item") даст нужный результат) Конечно, в данном случае это не дает оптимизации, просто перенос с одного формата в другой. Но если этот параметр используется более чем 1 раз - то это дает экономию столько раз, сколько он используется. В частности прописывание параметра scient = true во все броники, перечисленные в art_hit.scient полностью избавляет нас от этой таблицы. А также, если сделать вот такую секцию: [iI_ATTCH]:identity_immunities GroupControlSection = spawn_group discovery_dependency = $spawn = "devices\quest_items\bandranen_pda" ;$prefetch = 32 class = II_ATTCH cform = skeleton radius = 1 И затем написать вместо: [bandranen_pda]:identity_immunities, protected_item вот так: [bandranen_pda]:II_ATTCH, protected_item То тогда в каждой секции на классе II_ATTCH можно выкинуть все перечисленные выше строки, вынесенные в общую секцию. А это только в оригинале ТЧ более 500 ненужных и дублирующихся строк. А если посмотреть по другим классам, и добавить всё, сделанное в модах на оригинал, то количество вырастет на несколько порядков. И этот весь дубликат висит балластом в памяти всю игру, провоцируя вылеты по нехватке ресурсов. Повторюсь: жаль, что понимание этого ко мне пришло только недавно, уже после релиза ОП-2. Иначе в нем можно было еще очень и очень много чего оптимизировать и упростить) Подобного еще можно написать много, я изложил только то, что первое пришло на ум, но надеюсь суть и принципы изложенного понятны) все остальное оптимизируется по аналогии. Надеюсь этот пост окажется кому-то полезным)
  3. Справочник по функциям и классам

    В дополнение к таблице _G: Если через кейлоггер или еще как-то вызвать команду _G[имя скрипта] = nil, то движок вновь перекомпилирует указанный скрипт при первом к нему обращении. Что это дает? Это дает то, что если вы отлаживаете какой-либо код, то нет необходимости делать сейв/лоад после каждой правки. Если мы, допустим, правим файл amk.script, то достаточно после сохранения правок через кейлоггер вызвать _G.amk = nil и все - движок перекомпилирует его по новой и все изменения тут же вступят в силу без очередного сейв/лоада. Жаль, что эту фичу я для себя открыл только сейчас. Сколько времени можно было бы сэкономить. Это работает для всех файлов кроме биндеров. Дело в том, что для каждого объекта биндер зачем-то компилируется отдельно, поэтому чтобы увидеть изменения, например в bind_monster.script, то нужно написать _G.bind_monster = nil и заспавнить нового монстра. И на новом объекте изменения уже будут применены.
  4. Разговоры о Народной Cолянке 2010 и дополнениях к ней

    Это из мастераддона. Я вводил этот поршень, чтобы нормально сдавались по хомячеству особые предметы. Для чистой Соли - не нужен. В ОП-1 он стоит везде, где надо, только про Гавра я забыл) в ОП-2 также будет стоять везде где надо. Без него при отбирании контейнеров, спальников и маячков будут выскакивать соответствующие меню, при отбирании энергетиков ГГ не будет хотеть спать и т.д. Это поршень на время его активности отключает срабатываение калбеков на потерю особых предметов) Почему у одних вылетает, а у других - нет, я не знаю. Видимо разные сборки. Только что глянул чистую соль от Архары из шапки темы, на которой собирался ОП-1 - там этой правки нет)
  5. Разговоры о Народной Cолянке 2010 и дополнениях к ней

    По замкам: только что проверил сапсановскую правку - вылетает точно с тем же логом, что и без нее. В данном случае эта доп проверка, что именно убрали замок из рюкзака, не имеет смысла, потому что сама функция zamok.remove() вызывается из калбека на взятие предмета из invbox, в котором эта проверка уже стоит в движке. То есть этот калбек, а следовательно и функция, не вызывается, если box:clsid() не будет равно clsid.inventory_box. Поэтому эта правка ничего не меняет. Далее: вылет происходит не в функции remove(), в которой дописана проверка, а в функции add(), котора вызывается из калбека на потерю предмета. Вот и получается, что замок удалился из игры при отравлении Гавром, а здесь мы пытаемся получить его серверный объект, которго уже нет, отсюда и вылет с руганью на nil. А вот как раз таки моя правка, добавляющая проверку поршня, и закрывает этот вылет. Я когда делал хомячество, долго пытался понять, что же в этом скрипте делается с замком, и почему функция с именем add вызывается из калбека на потерю, и тоже пытался что-то тут выправить) но в итоге остановился на универсальном варианте, который закрывает не только этот вылет, но и все другие проблемы при удалении из инвентаря всех других предметов, обрабатывающихся особым образом: контейренов для артов, спальников, маячков и т.д. Просто перед удалением выдаем поршень biznes_remove_special_item а после - снимаем. И во всех калбеках, как и в замке, дописываем проверку этого поршня. И тогда особый предмет удаляется корректно - без вылетов и срабатываения калбеков на его потерю) Поэтому в ОП-2 функция удаления предметов при отравлении Гавром выклядит вот так: function release_actor_items() local obj db.actor:give_info_portion("biznes_remove_special_item") db.actor:iterate_inventory( function(dummy,item) -- Документы Воронина спецом вынесены отдельно, т.к. почему-то через protected_items 2 штуки все равно удалялись if item:section()~="zone_docs" and not protected_items.actor_items_keep(item:section()) then -- удаление вещи alife():release(alife():object(item:id())) end end ,db.actor) db.actor:disable_info_portion("biznes_remove_special_item") т.е. все удаляется между поршнем) а в ОП-1 я забыл сюда этот поршень поставить) поэтому по хомячеству замки сдаются нормально - без вылетов, а по Гавру - вылетает)) То есть если в скрипт ОП-1 поставить выдачу и снятие этого поршня, как выше - то вылетов у Гавра по замкам не будет) Или, вариант для чистой Солянки, где нет этого поршня: дописать после строки local sitem = alife():object(item:id()) -- получаем серверный объект строку if not sitem then return end и все - вылетов также не будет) Этот вариант также подойдет и для ОП-1)
  6. Скриптование

    Совершенно случайно нашел истинную причину, почему бьются сейвы в Лиманске, если сохраниться рядом зомби и изломами, бились сейвы в ОП-1 в Путепроводе, бьются сейвы если не зачистить территорию после взятия некоторых тайников Кости, когда спавнятся зомбированные сталкеры и зомби одновременно. Вот цитата со stalkerwiki: В оригинале ОГСМ и основанных на нём модах часто встречались проблемы с сохранениями на Радаре. Эту проблему долго не удавалось победить, пока наконец благодаря помощи Маландринуса не удалось выявить её первопричину. Как выяснилось, она очень проста - гражданские зомби в моде (монстры) имели в конфиге ту же пропись вида (параметр конфига species), что и монолитовцы и зомбированные (неписи). И там и тут было проставлено "zombie", и так оно было ещё с оригинала. Как оказалось, так делать категорически нельзя. Дело в том, что у неписей есть такой функционал, как хитовая память - в ней какое-то время хранятся ссылки на атакующие объекты. У монстров тоже есть остатки этого функционала, но он неработоспособен, и использовать его нельзя. В случае же когда монстры и неписи попадают в один вид, в ситуации когда они находятся рядом в бою, хитовая память монстров автоматически получает от неписей того же вида распространяемую внутри вида информацию об атакующих - а хранить её монстрам нельзя. Если после создания такой ситуации сохраниться - сейв будет вызывать вылет при загрузке. То есть проще говоря, если в бою с монолитовцами рядом оказывались гражданские зомби - и игрок сохранял игру - сейв этот не загружался. Чтобы предотвратить эти проблемы, вполне достаточно создать для гражданских зомби свой отдельный вид, добавив его прописи в конфиг game_relations. так и сделал) оставил у всех сталкеров species = zombie а всем зомби и изломам поставил species = zombi завел эту новую группу в game_relations.ltx и поставил ей такие же параметры друг-враг, как и у zombie загрузил имевшийся у меня сейв в Лиманске, и сохранился у фонтана, где бегали и неписи и моснтры зомби, и загрузил этот сейв. И - о чудо - сейв загрузился!!! То есть бились сейвы, где зомби-неписи и зомби-монстры были рядом. Подобное есть по тайникам Кости, где идет спавн при взятии тайника - там была такая же проблема) теперь и она решена)) По этой же причине в солянке не работали изломы в x-16 и Архара был вынужден их убрать оттуда из спавна - потому что там терлись неписи/зомби, и они вместе приходили в онлайн. На Янтаре нет битья сейвов потому, что там нет монстров зомби и изломов, а иначе была бы та же проблема)) Здорово, только вот пост не совсем в тему... ColR_iT
  7. Скриптование

    Наконец-то победил причину автозавершения квестов на защиту барьера и им подобным после сейв/лоада) Найдена и вырвана с корнем глубоко сидевшая в скриптах ошибка еще от ПЫСов, что в сейве не сохранялся ИД смарта, от которого надо защищать другой смарт) Этот ИД задавался при выдаче таска, но при сейв/лоаде он терялся, и после лоада это ИД было = nil. Но ее легко было бы выловить, если бы при запросе состояния несуществующего гулага возвращалось заведомо несуществующее значение, например -1. Но xr_gulag.getGulagState() при несуществующем гулаге возвращает 0, или состояние неактивного, пустого гулага. Вот проверка и срабатывала, что гулаг зачищен, и задание выполнялось)) Это, конечно, досадная оплошность со стороны того, кто делал скрипты гулагов, и, если бы не она, то это все было бы выявлено и поправлено еще в далеком 2007 году) а так эта проблема дожила аж до 2014 года)) И, наконец, она вылечена)) Правка этой ошибки в общем случае требует НИ, так как в нетпакет пишется новое значение и меняется его размер. Но можно использовать технологию двухэтапного подключения этой и подобных ей правок, без начала НИ. Для этого нужно в методе save выдать поршень, и в методе load его проверять при чтении нетпакета. Тогда на старых сейвах до правки будет читаться старый нетпакет, а на новых - новый) Вот правка автозавершения на task_manager от Народной Солянки на версии 1.0006: -- Будем записывать не id задания а его хеш - семикратная экономия. function CRandomTask:save(p) printf("^^^ SAVE") -- Отметка того, что это новая версия формата. p:w_u8(255) --' Считаем количество записей local i = 0 for k,v in pairs(self.task_info) do i = i + 1 end p:w_u8(i) for k,v in pairs(self.task_info) do if not id_to_hash[k] then abort("Cannot find hash for id %s!",k) end p:w_u16(id_to_hash[k]) p:w_bool(v.enabled) p:w_bool(v.enabled_props) if not status_to_num[v.status] then abort("Wrong status '%s' for task %s!",v.status,k) end p:w_u8(status_to_num[v.status]) p:w_u32(v.selected_target or -1) p:w_u32(v.defend_target or -1) -- Фикс автозавершения квестов utils.w_CTime(p, v.last_task_time) end --' Та же самая процедура с активными тасками i = 0 for k,v in pairs(self.active_task_by_type) do i = i + 1 end p:w_u8(i) for k,v in pairs(self.active_task_by_type) do if not ct_to_hash[k] then abort("Cannot find hash for complex type %s!",k) end p:w_u16(ct_to_hash[k]) if not id_to_hash[v] then abort("Cannot find hash for task id %s!",v) end p:w_u16(id_to_hash[v]) end -- Фикс автозавершения квестов db.actor:give_info_portion("fix_task_manager") end --' Загрузка function CRandomTask:load(p) printf("^^^ LOAD") --' Считаем количество записей local rt0=p:r_tell() local i = p:r_u8() amk.mylog("tasks "..i) if i~=255 then for k = 1,i do local id = p:r_stringZ() if id ~= nil and self.task_info[id] ~= nil then self.task_info[id].enabled = p:r_bool() self.task_info[id].enabled_props = p:r_bool() self.task_info[id].status = p:r_stringZ() local selected_target = p:r_u32() if selected_target ~= -1 then self.task_info[id].selected_target = selected_target end -- Фикс автозавершения квестов if has_alife_info("fix_task_manager") then local defend_target = p:r_u32() if defend_target ~= -1 then self.task_info[id].defend_target = defend_target end end self.task_info[id].last_task_time = utils.r_CTime(p) end end --' Та же самая процедура с активными тасками local i = p:r_u8() amk.mylog("active "..i) for k = 1,i do local id = p:r_stringZ() self.active_task_by_type[id] = p:r_stringZ() end else i=p:r_u8() for k = 1,i do local hash = p:r_u16() local id=hash_to_id[hash] if not id then abort("Cannot find id for hash %d!",hash) end self.task_info[id].enabled = p:r_bool() self.task_info[id].enabled_props = p:r_bool() self.task_info[id].status = num_to_status[p:r_u8()] local selected_target = p:r_u32() if selected_target ~= -1 then self.task_info[id].selected_target = selected_target end -- Фикс автозавершения квестов if has_alife_info("fix_task_manager") then local defend_target = p:r_u32() if defend_target ~= -1 then self.task_info[id].defend_target = defend_target end end self.task_info[id].last_task_time = utils.r_CTime(p) end --' Та же самая процедура с активными тасками i = p:r_u8() amk.mylog("active "..i) for k = 1,i do local cthash = p:r_u16() local id=hash_to_ct[cthash] if not id then abort("Cannot find complex type for hash %d!",cthash) end local hash=p:r_u16() self.active_task_by_type[id] = hash_to_id[hash] if not self.active_task_by_type[id] then abort("Cannot find task id for hash %d!",hash) end end amk.mylog("Feel the difference.") end amk.mylog("size "..p:r_tell()-rt0) end Если адаптация к старым сейвам не нужна, то можно выкинуть поршень fix_task_manager и все его проверки.
  8. Инструментарий для мододелов

    Привет! Добрый человек прислал мне вот эту прогу:http://rusfolder.com/39246424 Эта прога позволяет просматиривать и, что самое главное, редактировать настройки дальностей сиышимости звуков в Сталкере без использования СДК. Крайне удобно, когда нужно подобрать дальности слышимости или громкость без необходимости после каждой правки каждый раз прогонять звук через СДК. Один раз прогнал - и дальше настраиваешь уже в этой проге. Прога импортная, поэтому все на инглише. Но там все просто - разберетесь. Чтобы открылись ссылки на форум и тему в ридми на сайте gsc-game.com, переключите сайт на английский режим перед открытием ссылок) Думаю, имеет смысл вынести этот пост в шапку этой темы, ибо многим она будет полезна) Ссылку поправил. Была нечитаема. BFG
  9. Справочник вылетов

    Людмила, есть запрет)) вот его логика: [smart_terrains] none = true [logic] active = mob_home on_death = death on_hit = hit [mob_home] path_home = yantar_kontroller_yazva_walk home_min_radius = 15 home_max_radius = 20 aggressive_home on_signal = sig_attacked | mob_combat [mob_combat] on_timer = 30000 | mob_home [death] on_info = {=killed_by_actor_eagle} %=arhara_dialog.fotka_kont_yazva_have% [hit] on_info = {=hit_by_actor_eagle} %=arhara_dialog.fotka_kont_yazva_have% То, что запрет стоит не в алспауне а вынесен в cfg файл, ничего не меняет - все работает в обоих вариантах. Вот скрипт из xr_logic, обрабатывающий этот момент: local filename = utils.cfg_get_string(ini, section_logic, "cfg", npc, false, "") if filename then printf("_bp: enable_scripts: object '%s' has external configuration file '%s'", npc:name(), filename) -- Рекурсивно обработать конфигурационный файл, на который ссылается поле cfg actual_ini_filename = filename actual_ini = ini_file(filename) return configure_schemes(npc, actual_ini, actual_ini_filename, stype, section_logic, gulag_name) тут просто рекурсивно вызывается чтение схем уже из другого ini файла. И запрет по смартам также читается) проблема именно в том, что я написал) Если ему поставить walker - то сразу вылет по путям. И я спавнил его, находясь в туннеле рядом с ним, т.е. он сразу был в онлайне. А в гулаги объект с логикой движок затягивает, мне думается, только если он находится в оффлайне. Сам лично с этим столкнулся, когда начинал спавнить неписей, и забыл прописать запрет на смарт) Непись четко был на месте и отыгрывал логику, пока он был в онлайне. Но стоило мне уйти с локи и вернуться, как он пропадал) А здесь контрик сразу выходил из-под логики home, сразу после спавна, находясь в онлайне. И вылет по путям сразу после спавна при прописывании схемы walker также говорит об этом, ибо ему просто некуда идти - все пути отрезаны рестрикторами) А если бы не было запрета на смарт, то ничего бы не вылетало - он просто уходил бы в гулаг и все. А когда я прописал ему этот рестриктор, то все - и вылет по walkery пропал - он стоял в точке, и home заработал - он никуда не уходит) Так что проблема была именно в этом) ЗЫ: а насчет прописывания запрета на смарты в алспауне, а не в конфигурационном файле я тоже сначала думал, что не будет работать) но потом покопался в алспауне и увидел, что так (запрет стоит в cfg) стоит в Соли у Молнии в МГ - dead_city_molniy. А также у некоторых ООПшных персонажей. И никто ни разу не жаловался, что они куда-то пропадают)
  10. Справочник вылетов

    Решил поделиться, как мне думается, полезной информацией для мододелов, т.к. поиском особо ничего не находится, а с подобной проблемой я уже сталкивался не раз) Суть в том, что мы спавним непися/монстра с конкретной логикой и путями, и при спавне спустя несколько секунд получаем вылет any vertex in patrol path... И ничего не понятно: АИ сетка есть, причем сплошная, никого и ничего рядом, но вылетает стабильно. Как я выяснил опытным путем, проблема в том, что непися/монстра удерживают или не пускают in или out рестрикторы. Т.е., чтобы этот вылет ушел, нужно в алспауне прописать объекту строку base_out_restrictors = [имя ограничивающего рестриктора] или base_in_restrictors = [имя ограничивающего рестриктора] Причем эта проблема есть не на всех локах, а только на тех, где ПЫСы зачем-то понаставили этих ограничивающих рестрикторов. Назначение их мне не совсем понятно, ведь зону нахождения любого монстра/непися можно ограничить его логикой mob_home, walker и т.д - зачем еще эти дополнительные ограничения в виде зон? Я сталкивался с этой проблемой на Янтаре, Х-16 и на ЧАЭС-2. Причем, если у монстра прописана логика mob_home, но не задана указанная выше строка, то монстр молча выходит из-под этой логики и передается под управление движком, т.е. затягивается в любой свободный гулаг. Эта проблема до сегодняшнего дня имела место с Соляночным квестом на фото контролера в туннеле на Янтаре, когда он, находясь под логикой mob_home, тем не менее постоянно уходил в разные гулаги Зоны, и квест выполнить было очень проблематично. Я для пробы прописал ему логику walker с одной точкой walk и look, и сразу получил указанный выше вылет. Тогда я прописал ему в алспауне вот эту строку: ; cse_alife_monster_abstract properties base_out_restrictors = yantar_tunnel_restrictor_4 И все - и вылеты пропали, и контрик никуда не уходит) т.е. злосчастная проблема с ним наконец решена) рестриктор я выбрал по координатам, ближайший, который был прописан одному из снорков, которые спавнятся в туннеле) Может, эта информация пригодится мододелам в их нелегком труде))
  11. [SoC] Ковыряемся в файлах

    Еще вопрос возник: Можно ли как-то отследить, что гг погиб именно от аномалии? Неважно какой, просто от аномалии? Я вижу пока только вариант проверки по расстоянию до ближайшей аномалии, но он чреват ложнгыми срабатываниями, когда гг застрелили рядом с аномалией) Есть ли какой надежный способ определить это в ТЧ?
  12. Скриптование

    Artos, последний вопрос: как может быть хит "пустой" (amount=0), если непись погиб от одного-единственного выстрела в голову? Из ствола актора. При этом он стоял на абсолютно ровной открытой местности, т.е. ни за что не цеплялся, и погиб именно от пули актора? А у меня во вчерашнем, более полном тесте, также, как и у тебя, amount практически везде = 0, и это при том, что я зачистил весь АТП - более 15 бандитов? Они все что, погибли, споткнувшись об ветки?) Или я все ещё чего-то не понимаю, а в ТЧ хит калбек работает правильно, и amount=0 в момент, когда непись погибает - это именно так и должно быть?
  13. Скриптование

    Господа! Всё, что вы написали выше, про умное выпадение и прочее - это всё относится к монстрам. А я спрашивал про неписей. То, что для монстров кость передается, я даже проверять не буду - по скриптам видно, что она обрабатывается и работает. А вот для неписей - она всегда = 0. Убедиться в этом очень просто: в мотиваторе в самом начале hit_callback напишите вот это: get_console():execute("load ~~~ npc: "..self.object:name().." bone_index:"..bone_index) и постреляйте по неписям по разным частям их тела. Сами всё увидите) Вот вырезка из моего лога, когда я воевал с бандитами на АТП: ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_125265 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_125265 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~ spawn now [respawn30856] -> [ghoul_strong24093] ! Cannot find saved game ~ spawn now [respawn30856] -> [m_poltergeist_strong_flame24198] ! Cannot find saved game ~ spawn now [respawn30856] -> [ghoul_strong24200] sv reject. id_parent [0][actor:single_player] id_entity [4278][ammo_9x39_sp5:ammo_9x39_sp54278] [9134] sv destroy object [4278][ammo_9x39_sp5:ammo_9x39_sp54278] [9134] cl setDestroy [4278][9135] sv destroy object [24130][separator:separator24130] [9136] sv reject. id_parent [0][actor:single_player] id_entity [24130][separator:separator24130] [9136] cl setDestroy [24130][9136] ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_125265 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_125265 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 sv reject. id_parent [29318][atp_fabrika_bandit_respawn_1:atp_fabrika_bandit_respawn_129318] id_entity [13492][ammo_5.45x39_ap:ammo_5.45x39_ap] [9219] sv destroy object [13492][ammo_5.45x39_ap:ammo_5.45x39_ap] [9219] cl setDestroy [13492][9220] ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: val_bandit_respawn_438920 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 sv destroy object [9506][grenade_rgd5:grenade_rgd59506] [9230] sv reject. id_parent [38920][val_bandit_respawn_4:val_bandit_respawn_438920] id_entity [9506][grenade_rgd5:grenade_rgd59506] [9230] sv destroy object [14883][grenade_f1:grenade_f114883] [9230] sv reject. id_parent [38920][val_bandit_respawn_4:val_bandit_respawn_438920] id_entity [14883][grenade_f1:grenade_f114883] [9230] sv destroy object [9366][yad:yad9366] [9230] sv reject. id_parent [38920][val_bandit_respawn_4:val_bandit_respawn_438920] id_entity [9366][yad:yad9366] [9230] sv destroy object [9323][bandage:bandage9323] [9230] sv reject. id_parent [38920][val_bandit_respawn_4:val_bandit_respawn_438920] id_entity [9323][bandage:bandage9323] [9230] sv destroy object [9396][medkit:medkit9396] [9230] sv reject. id_parent [38920][val_bandit_respawn_4:val_bandit_respawn_438920] id_entity [9396][medkit:medkit9396] [9230] sv destroy object [38915][device_pda:device_pda38915] [9230] sv reject. id_parent [38920][val_bandit_respawn_4:val_bandit_respawn_438920] id_entity [38915][device_pda:device_pda38915] [9230] sv destroy object [38923][ammo_5.56x45_ap:ammo_5.56x45_ap38923] [9230] sv reject. id_parent [38920][val_bandit_respawn_4:val_bandit_respawn_438920] id_entity [38923][ammo_5.56x45_ap:ammo_5.56x45_ap38923] [9230] sv destroy object [38947][device_torch:device_torch38947] [9230] sv reject. id_parent [38920][val_bandit_respawn_4:val_bandit_respawn_438920] id_entity [38947][device_torch:device_torch38947] [9230] sv destroy object [38923][NOTFOUND] [9230] !SV:ge_destroy: [38923] not found on server cl setDestroy [9506][9231] cl setDestroy [14883][9231] cl setDestroy [9366][9231] cl setDestroy [9323][9231] cl setDestroy [9396][9231] cl setDestroy [38915][9231] cl setDestroy [38923][9231] cl setDestroy [38947][9231] ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 sv reject. id_parent [38920][val_bandit_respawn_4:val_bandit_respawn_438920] id_entity [38948][wpn_l85:wpn_l8538948] [9232] ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 sv reject. id_parent [29339][atp_fabrika_bandit_respawn_1:atp_fabrika_bandit_respawn_129339] id_entity [21405][ammo_5.45x39_fmj:ammo_5.45x39_fmj] [9305] sv destroy object [21405][ammo_5.45x39_fmj:ammo_5.45x39_fmj] [9305] cl setDestroy [21405][9306] sv reject. id_parent [29339][atp_fabrika_bandit_respawn_1:atp_fabrika_bandit_respawn_129339] id_entity [24462][grenade_rgd5_test:grenade_rgd5_test24462] [9439] sv reject. id_parent [29339][atp_fabrika_bandit_respawn_1:atp_fabrika_bandit_respawn_129339] id_entity [24463][grenade_rgd5_test:grenade_rgd5_test24463] [9439] ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: agr_bandit_respawn_138926 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 sv destroy object [9372][yad:yad9372] [9456] sv reject. id_parent [38926][agr_bandit_respawn_1:agr_bandit_respawn_138926] id_entity [9372][yad:yad9372] [9456] sv destroy object [9400][medkit:medkit9400] [9456] sv reject. id_parent [38926][agr_bandit_respawn_1:agr_bandit_respawn_138926] id_entity [9400][medkit:medkit9400] [9456] sv destroy object [9401][bandage:bandage9401] [9456] sv reject. id_parent [38926][agr_bandit_respawn_1:agr_bandit_respawn_138926] id_entity [9401][bandage:bandage9401] [9456] sv destroy object [38927][device_pda:device_pda38927] [9456] sv reject. id_parent [38926][agr_bandit_respawn_1:agr_bandit_respawn_138926] id_entity [38927][device_pda:device_pda38927] [9456] sv destroy object [38959][ammo_12x70_buck:ammo_12x70_buck38959] [9456] sv reject. id_parent [38926][agr_bandit_respawn_1:agr_bandit_respawn_138926] id_entity [38959][ammo_12x70_buck:ammo_12x70_buck38959] [9456] sv destroy object [38961][device_torch:device_torch38961] [9456] sv reject. id_parent [38926][agr_bandit_respawn_1:agr_bandit_respawn_138926] id_entity [38961][device_torch:device_torch38961] [9456] sv destroy object [38962][guitar_a:guitar_a38962] [9456] sv reject. id_parent [38926][agr_bandit_respawn_1:agr_bandit_respawn_138926] id_entity [38962][guitar_a:guitar_a38962] [9456] sv destroy object [38959][NOTFOUND] [9456] !SV:ge_destroy: [38959] not found on server cl setDestroy [9372][9457] cl setDestroy [9400][9457] cl setDestroy [9401][9457] cl setDestroy [38927][9457] cl setDestroy [38959][9457] cl setDestroy [38961][9457] cl setDestroy [38962][9457] sv reject. id_parent [38926][agr_bandit_respawn_1:agr_bandit_respawn_138926] id_entity [38964][wpn_bm16:wpn_bm1638964] [9458] ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_232020 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129339 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_330071 bone_index:0 ! Cannot find saved game ~~~ npc: atp_fabrika_bandit_respawn_129318 bone_index:0 Как видно из лога - кость не работает. Я стрелял по разным частям тела, рукам, ногам, туловищу, взрывал неписей гранатами - результат один) Ну да ладно) я могу обойтись без этого, просто хотел кое-что сделать по неписям, но обойдусь без него))
  14. Скриптование

    Artos, попробовал. Да, так работает, только у неписей bone_index при любом хите всегда = 0. Похоже в ТЧ этот параметр просто не обрабатывается. И я не нашел ни одного использования этого параметра в чистом ТЧ и в Солянке. Этот параметр просто передается из функции в функцию, гуляя по логике и калбекам, но нигде не проверяется на значение...
  15. Скриптование

    Господа, подскажите, можно ли как-то проверить, что ГГ убил непися именно хедшотом? Т.е. смертельный выстрел попал в кость головы (bip01_head)? В мотиваторе в hit_callback передается кость, по которой прошел хит, а в death_callback - нет. Можно ли как-то решить эту задачу?
×