В данной теме вы можете задавать любые вопросы касательно S.T.A.L.K.E.R. моддинга
• Не флудить • Предварительно просматривайте раздел, ведь ответ на ваш вопрос может быть там • В своем вопросе указывайте платформу моддинга — Тень Чернобыля, Чистое небо или Зов Припяти
1. Какая стоит игра, с каким патчем? 2. Какой мод, версия мода? 3. Что правили своими ручками? 4. Лог вылета и последние 25 строк (помещать под спойлер).
Структура папок и файлов в корневом каталоге игры:
...\S.T.A.L.K.E.R\gamedata\anims – папка содержит исполнительные файлы эффектов (например от ПНВ).
...\S.T.A.L.K.E.R\gamedata\config – папка содержит основные конфигурационные файлы (т. е. большинство настроек игры)
...\S.T.A.L.K.E.R\gamedata\meshes – содержит модели игровых предметов и персонажей...
...\S.T.A.L.K.E.R\gamedata\scripts – папка со скриптами (рабочими файлами содержащими в себе наборы функций) – основная папка, отвечающая за ответные действия игры и действия производимых игроком в игре.
...\S.T.A.L.K.E.R\gamedata\shaders – папка содержит в себе конфигурационные файлы шейдеров.
...\S.T.A.L.K.E.R\gamedata\sounds – здесь находятся все звуки игры (разложены по своим каталогам и папкам)
...\S.T.A.L.K.E.R\gamedata\spawns – содержит файл спавна – очень важный файл – не трогать без нужды!!!
...\S.T.A.L.K.E.R\gamedata\textures – содержит разложенные по каталогам и папкам текстуры используемые в игре.
Теперь разберем папки в каталоге «config»
...\S.T.A.L.K.E.R\gamedata\config\creatures - содержит массу конфигурационных файлов, в основном отвечающих за взаимодействие Главного героя игры (в дальнейшем ГГ) и прочего окружения в игре и ТТХ самого ГГ.
...\S.T.A.L.K.E.R\gamedata\config\gameplay – содержит конфиг. файлы персонажей игры (НПС) отвечающие за внешний вид, статус, снаряжение. Файлы: character_desc_ххх (где ххх – название локации) и character_desc_general (отвечает за зомбированного персонажа). Также содержит файлы диалогов и профилей НПС.
…\S.T.A.L.K.E.R\gamedata\config\misc – конфиг.файлы торговцев (папки с именами торговцев), артефактов, брони, квестовых предметов, уникальных предметов, файл отвечающий за награды за автозадания, файл эффектов (алкоголизма, ранения, ПНВ и прочих)...
…\S.T.A.L.K.E.R\gamedata\config\mp – среди прочих содержит важный файл mp_ranks – отвечающий за выпадение оружия и патронов из рук ГГ и НПС – без прописывания добавляемого в игру оружия в этот файл при выпадении нового оружия из рук ГГ\НПС будут следовать вылеты.
…\S.T.A.L.K.E.R\gamedata\config\text\rus – содержит файлы описаний всего и вся находящегося в игре (брони, артефактов, оружия, предметов и прочего).
…\S.T.A.L.K.E.R\gamedata\config\weapons – содержит конфиг.файлы оружия и боеприпасов используемых в игре.
…\S.T.A.L.K.E.R\gamedata\config\weathers – содержит конфиг.файлы настройки погоды на локациях.
Теперь немного подробнее о файлах.
...\S.T.A.L.K.E.R\gamedata\config\misc:
Папка shop_ххх (ххх – имя торговца) – содержит конфиг.файлы ассортимента торговца.
outfits – содержит секции конфигов костюмов.
artefacts - содержит секции конфигов артефактов.
items - содержит секции конфигов предметов.
monster_items - содержит секции конфигов частей монстров
postprocess - содержит секции конфигов пост. процессов (например: ПНВ).
quest_items - содержит секции конфигов квестовых предметов.
task_manager - содержит секции наград за автоквесты.
unique_items - содержит секции конфигов уникального оружия и костюмов.
Перенес нужные папки в SDK/ gamedata, захожу в Level Editor и при нажатии на Spawn Element, он пишет что практически все секции дублированы. Что делать?
13Шустрый13, Ругается он на повторные $spawn Открываешь папку \gamedata\config\weapons\, дальше первый ствол, в нём: [wpn_abakan]:identity_immunities $spawn = "weapons\abakan" ; путь для сдк. Если в этом доке есть второй ствол [wpn_bla_bla_bla]:wpn_abakan то добавляешь\исправляешь: $spawn = "weapons\wpn_bla_bla_bla" ; путь для сдк.
local npc_psy = {} local npc_run = {} local npc_sit = {} local npc_go = {}
-- We check whether NPC is in specific rectangle zone (are set for special places, -- such as bar, where NPCs should not react to blowout at all) function npc_in_zone(obj,lev,pos_psy_x,pos_psy_y,size_psy_x,size_psy_y,z1,z2) local level_name = level.name() if level_name ~= lev then return false end local pos = obj:position() local x1 = pos_psy_x local x2 = pos_psy_y local y1 = size_psy_x local y2 = size_psy_y if (pos.x >= x1 and pos.x <= x2) and (pos.z >= y1 and pos.z <= y2) and (pos.y >= z1) and (pos.y <= z2) then return true end return false end
-- We get the nearest to NPC hide function get_nearest_hide(npc) local hideout_list = {} for k,v in pairs(restrictor_list) do local community, radius = get_community_hide(v) local obj = level.object_by_id(v.id) if obj and string.find(community, npc:character_community()) then local npc_pos = npc:position() local hide_pos = obj:position() local distance = npc_pos:distance_to(hide_pos) local hide = {obj = obj, rad = radius, dist = distance} table.insert(hideout_list, hide) end end table.sort(hideout_list, function(a,b) return a.dist < b.dist end) local nearest_hide = hideout_list[1] return nearest_hide end
-- We get the hideout data (communities, radius) function get_community_hide(obj) if not obj then return "none" end local packet = net_packet() obj:STATE_Write(packet) local game_vertex_id = packet:r_u16() local cse_alife_object__unk1_f32 = packet:r_float() local cse_alife_object__unk2_u32 = packet:r_s32() local level_vertex_id = packet:r_s32() local object_flags = packet:r_s32() local custom_data = packet:r_stringZ() local cd = parse_custom_data(custom_data) if not cd.parameters then return "none" end if not cd.parameters.community then return "none" end if not cd.parameters.radius then return "none" end return cd.parameters.community, cd.parameters.radius end
function is_in_specific_zone(npc) if npc_in_zone(npc,"l01_escape",-256,-246,-137,-132,-25,-20) or -- Бункер Сидора npc_in_zone(npc,"l03_agroprom",-198.31,-195.66,85.4,96.54,2,5.3) or -- Вагон дезертира npc_in_zone(npc,"l04_darkvalley",30,50,-60,-25,-4,0) or -- Тюрьма в Темной долине npc_in_zone(npc,"l05_bar",123,140,18,30,-6,0) or -- Бар npc_in_zone(npc,"l05_bar",118,121,34,41,-4,1) or -- Охранник Бара npc_in_zone(npc,"l05_bar",149,158,67,74,0,4) or -- Приемная Арни npc_in_zone(npc,"l05_bar",136,168,73,134,-22,-10) or -- Арена npc_in_zone(npc,"l05_bar",208,234,120,139,-6,2) or -- База Долга npc_in_zone(npc,"l06_rostok",-90,-87,125,151,0,6) or -- Блокпост наемников npc_in_zone(npc,"l07_military",-27,-16,-33,-14,-9,0) or -- База Свободы npc_in_zone(npc,"l08_yantar",23,40,-282,-269,-16,0) or -- Бункер ученых npc_in_zone(npc,"l08_yantar",-265,-22,-218,-6,-20,-11) or -- Кишка npc_in_zone(npc,"l11_pripyat",-16,-2,188,204,-5,0) then -- Подвал ДК return true end return false end
function is_in_hide(npc) if npc_in_zone(npc,"l01_escape",-211,-198,-132,-125,-23,-20) or -- Подвал 1 в лагере новичков npc_in_zone(npc,"l01_escape",-216,-209,-133,-120,-24,-20) or -- Подвал 2 в лагере новичков npc_in_zone(npc,"l02_garbage",-112,-57,-6,25,-9,90) or -- Ангар на Свалке npc_in_zone(npc,"l05_bar",206,213,50,68,0,4) or -- Магазин Петренко npc_in_zone(npc,"l06_rostok",-285,-235,78,112,-7,0) or -- Тоннель Фримена npc_in_zone(npc,"l10_radar",639,664,167,189,-45,-37) or -- Секретная база Монолита npc_in_zone(npc,"l10_radar",86.73,153,-27,-21.70,-10,-4.6) or -- Вход в бункер npc_in_zone(npc,"l11_pripyat",-18,-12,58,83,-6,-3) or -- Подземный переход npc_in_zone(npc,"l11_pripyat",167,173,58,83,-6,-3) or -- Подземный переход npc_in_zone(npc,"l11_pripyat",-24,55,116,122,-4,0) then -- Канализация return true else local hide = get_nearest_hide(npc) if hide then if utils.npc_in_zone(npc, hide.obj) then return true end end end return false end
-- Spawn function. Better watch out :) function spawn_restrictor(p_level, p_vector, p_lv, p_gv, p_type, p_radius)
local p_name
p_name = p_level.."_hide_restrictor"
local obj = alife():create(p_name, p_vector, p_lv, p_gv)
local hide_name if string.find(p_type, "_") then hide_name = "ogsm_common_hide" else hide_name = "ogsm_"..p_type.."_hide" end
local mapspot if p_radius < 4 then mapspot = "ogsm_hide_spot_min" elseif p_radius < 11 then mapspot = "ogsm_hide_spot_mdl" else mapspot = "ogsm_hide_spot_max" end
local packet = net_packet()
obj:STATE_Write(packet)
-- свойства cse_alife_object local game_vertex_id = packet:r_u16() local cse_alife_object__unk1_f32 = packet:r_float() local cse_alife_object__unk2_u32 = packet:r_s32() local level_vertex_id = packet:r_s32() local object_flags = packet:r_s32() local custom_data = packet:r_stringZ() local story_id = packet:r_s32() local cse_alife_object__unk3_u32 = packet:r_s32()
-- свойства cse_shape local shape_count = packet:r_u8() local shape_type local center local radius
if shape_count == 0 then shape_type = 0 center = vector():set(0,0,0) radius = 10.0 shape_count = 1 else for i=1,shape_count do local shape_type = packet:r_u8() if shape_type == 0 then local center = packet:r_vec3() local radius = packet:r_float() else local v1 = packet:r_vec3() local v2 = packet:r_vec3() local v3 = packet:r_vec3() local v4 = packet:r_vec3() end end end
-- свойства cse_alife_space_restrictor local restrictor_type = packet:r_u8()
-- свойства cse_alife_object packet:w_u16(game_vertex_id) packet:w_float(cse_alife_object__unk1_f32) packet:w_s32(cse_alife_object__unk2_u32) packet:w_s32(level_vertex_id) packet:w_s32(object_flags)
local cd = parse_custom_data(custom_data) if not cd then cd={} end if not cd.parameters then cd.parameters = {} end cd.parameters.community = p_type cd.parameters.radius = p_radius custom_data = gen_custom_data(cd)
for i=1,shape_count do packet:w_u8(shape_type) if shape_type == 0 then packet:w_vec3(center) packet:w_float(p_radius) else packet:w_vec3(v1) packet:w_vec3(v2) packet:w_vec3(v3) packet:w_vec3(v4) end end
-- свойства cse_alife_space_restrictor packet:w_u8(restrictor_type)
-- Don't touch this too. function parse_custom_data(str) local t={} if str then for section, section_data in string.gfind(str,"%s*%[([^%]]*)%]%s*([^%[%z]*)%s*") do section = trim(section) t[section]={} for line in string.gfind(trim(section_data), "([^\n]*)\n*") do if string.find(line,"=")~=nil then for k, v in string.gfind(line, "([^=]-)%s*=%s*(.*)") do k = trim(k) if k~=nil and k~='' and v~=nil then t[section][k]=trim(v) end end else for k, v in string.gfind(line, "(.*)") do k = trim(k) if k~=nil and k~='' then t[section][k]="<<no_value>>" end end end end end end return t end function gen_custom_data(tbl) local str='' for key, value in pairs(tbl) do str = str.."["..key.."]\n" for k, v in pairs(value) do if v~="<<no_value>>" then str=str..k.." = "..v.."\n" else str=str..k.."\n" end end end return str end function trim (s) return (string.gsub(s, "^%s*(.-)%s*$", "%1")) end
-- Getting the list of hideouts on game load function get_level_hides() for i=1,65535 do local obj = alife():object(i) if obj then if string.find(obj:name(), level.name().."_hide_restrictor") then table.insert(restrictor_list, obj) end end end end
-- First run spawn. If parameter p_type is "fake_" - it means that the hide is fake - it is only for actor -- NPCs ignore such fake hides function first_run()
-- Создаем эвалуатор - проверяем, начался ли выброс class "evaluator_blowout" (property_evaluator) function evaluator_blowout:__init(name, storage) super (nil, name) self.st = storage end function evaluator_blowout:evaluate() if not self.object:best_enemy() and db.Flag2==1 and db.Dead2==0 and not (level.name()=="l11_pripyat" and self.object:character_community() == "monolith") and not is_in_hide(self.object) and not is_in_specific_zone(self.object) then self.st.blowout = true else self.st.blowout = false end return self.st.blowout == true end
-- Создаем эвалуатор - проверяем, потерял ли непись укрытие class "evaluator_hideout" (property_evaluator) function evaluator_hideout:__init(name, storage) super (nil, name) self.st = storage end function evaluator_hideout:evaluate() if db.Dead2==1 and not is_in_hide(self.object) and not is_in_specific_zone(self.object) then self.st.hideout_lost = true else self.st.hideout_lost = false end return self.st.hideout_lost == true end
-- Создаем эвалуатор - проверяем, сидит ли уже непись в укрытии class "evaluator_inhide" (property_evaluator) function evaluator_inhide:__init(name, storage) super (nil, name) self.st = storage end function evaluator_inhide:evaluate() if db.Flag2==1 and is_in_hide(self.object) then self.st.inhide = true else self.st.inhide = false end return self.st.inhide == true end
-- Создаем оператор - направляем НПС в укрытие class "action_hideout" (action_base) function action_hideout:__init(name, storage) super (nil, name) self.st = storage end function action_hideout:initialize() local npc = self.object npc:set_desired_position() npc:set_desired_direction() npc:clear_animations() npc:set_detail_path_type(move.line) npc:set_path_type(game_object.level_path) npc:remove_all_restrictions() if npc_run[npc:id()] ~= 1 then self.hide = get_nearest_hide(npc) if self.hide then npc:add_restrictions(self.hide.obj:name(), "") state_mgr.set_state(npc, "assault") else npc:remove_all_restrictions() state_mgr.set_state(npc, "hide") end npc_run[npc:id()] = 1 end end function action_hideout:execute() local npc = self.object npc:disable_talk() end function action_hideout:finalize() action_base.finalize(self) local npc = self.object npc_run[npc:id()] = 0 end
-- Создаем оператор - колбасим НПС, если он не нашел укрытие class "action_raskolbas" (action_base) function action_raskolbas:__init(name, storage) super (nil, name) self.st = storage end function action_raskolbas:initialize() local npc = self.object npc:set_desired_position() npc:set_desired_direction() npc:clear_animations() npc:remove_all_restrictions() local ran = math.random(1,2) if npc_psy[npc:id()] ~= 1 then if npc:character_community() == "monolith" then state_mgr.set_state(npc, "trans_1") else if ran == 1 then state_mgr.set_state(npc, "psycho_pain") else state_mgr.set_state(npc, "psy_pain") end end npc_psy[npc:id()] = 1 end end function action_raskolbas:execute() local npc=self.object npc:disable_talk() end function action_raskolbas:finalize() action_base.finalize(self) local npc = self.object npc_psy[npc:id()] = 0 end
-- Создаем оператор - усаживаем НПС, если он нашел укрытие class "action_inhide" (action_base) function action_inhide:__init(name, storage) super (nil, name) self.st = storage end function action_inhide:initialize() local npc = self.object npc:set_desired_position() npc:set_desired_direction() npc:clear_animations() npc:set_detail_path_type(move.line) npc:set_path_type(game_object.level_path) npc:remove_all_restrictions() self.hide = get_nearest_hide(npc) if self.hide then self.vertex = self.hide.obj:level_vertex_id() self.offset = vector():set(math.random()*3-1, 0, math.random()*3-1) self.offset:normalize() self.radius = math.random(1, self.hide.rad-1) self.lvid = npc:vertex_in_direction(self.vertex, self.offset, self.radius) if npc:level_vertex_id()~=self.lvid then state_mgr.set_state(npc,"raid") utils.send_to_nearest_accessible_vertex(npc, self.lvid) else state_mgr.set_state(npc,"hide") end else state_mgr.set_state(npc,"hide") end end function action_inhide:execute() local npc = self.object npc:disable_talk() if npc:level_vertex_id()~=self.lvid then if npc_go[npc:id()]~=1 then state_mgr.set_state(npc,"raid") utils.send_to_nearest_accessible_vertex(npc, self.lvid) npc_go[npc:id()] = 1 npc_sit[npc:id()] = 0 end else if npc_sit[npc:id()]~=1 then if npc:character_community()=="monolith" then state_mgr.set_state(npc,"trans_0") else state_mgr.set_state(npc,"hide") end npc_sit[npc:id()] = 1 npc_go[npc:id()] = 0 end end end function action_inhide:finalize() action_base.finalize(self) local npc = self.object npc_sit[npc:id()] = 0 npc_go[npc:id()] = 0 npc:remove_all_restrictions() end
-- Добавляем в планировщик нашу схему function add_to_binder(object, char_ini, scheme, section, st) local manager = object:motivation_action_manager() local property_wounded = xr_evaluators_id.sidor_wounded_base
action = manager:action(stalker_ids.action_danger_planner) action:add_precondition(world_property(property_hideout_lost, false)) end
-- Функции включения/выключения схемы function enable_scheme(npc, ini) local st = xr_logic.assign_storage_and_bind(npc, ini, "ogsm_hideout") st.enabled=true end function disable_scheme(npc, scheme) local st = db.storage[npc:id()][scheme] if st then st.enabled = false end end
---------------- Схема поведения НПС при выбросе для OGSM 2.x -----------------
If you're going to use the whole of this script or its parts in your own creative developments for the S.T.A.L.K.E.R. game, please don't become such a goddamn motherfucker like the notorious author of the ABC Mod - Carbrobro. Leave the copyrights, note the real author(s) and don't claim others' ideas and their realization to be your own ones. It's just simple Modmakers' Ethics. Thank you!
Если вы собираетесь использовать данный скрипт целиком или частично в своих разработках по игре S.T.A.L.K.E.R., пожалуйста не опускайтесь до уровня печально известного автора ABC мода - Carbrobro. Не удаляйте копирайты, указывайте настоящего автора(ов) и не выдавайте чужие идеи и их реализацию за свои. Ведь это элементарная этика модостроителей! Спасибо за понимание.
ТЧ, 1.0006. В каких случаях, происходят вылеты без лога, которые невозможно просмотреть, даже если есть скрипт для этого? Т.е. у меня есть специальный скрипт, для выявления причин вылета без лога, но произошёл вылет совершенно пустой.
ins33, Вот так понятнее: function npc_in_zone(obj,lev,X_min,X_max,Z_min,Z_max,Y_min,Y_max) Функция определяет попадание объекта в паралелипипед с данными параметрами.
if npc_in_zone(npc,"l01_escape",-256,-246,-137,-132,-25,-20) or -- Бункер Сидора
Далее: -- Бункер Сидора spawn_restrictor("l01_escape", vector():set(-249.9,-24.8,-134.4), 10136, 7, "fake_", 3) Только высота и ширина поменялись местами. Рестриктор спавнится по координатам: х=-249,9 , размер рестриктора -256,-246, 10 метров по диагонали х. z = -24.8, высота рестриктора ,-25,-20 , 5 метров y = -134.4, ширина тоже 5 метров. -137,-132
Попадая в эту зону НПС переходят в анимацию сидения. x,y,z мог напутать, что ширина, что длина. Но смысл, думаю ясен. А! Ну вот denis2000 более лаконичнее ответил.
Сообщение отредактировал Arist - Понедельник, 13.06.2016, 20:27
При этом нпс идут в укритие, те что в рестрикторе, садятся, те что не вошли в него стоят. Тут и возник вопрос, а нужены ли вообще эти паралелипипеды? Темболее с такими сложными координатами.
Поправьте, если ошибаюсь: паралелипипед тут играет роль шейпа привязанного к рестриктору? Если, да то может стоит использовать вместо spawn_restrictor ф-цию в которой можно указывать в качестве спавна рестриктора box?
Вам это очень нужно? Да, отображение выбранной анимации НПС в SDK удобно или даже красиво, но абсолютно не нужно, прекрасно можно обойтись. Итак три клика: 1. Открыть свойства объекта (Properties). 2. Выбрать анимацию (Animation) из выпадающего списка списка (Select Skeleton Animation). 3. Закрыть свойства объекта (Х).
Сообщение отредактировал denis2000 - Вторник, 14.06.2016, 10:23