В данной теме вы можете задавать любые вопросы касательно S.T.A.L.K.E.R. моддинга.
Не флудить
Предварительно просматривайте раздел. Ответ на ваш вопрос может быть там.
В своем вопросе указывайте платформу моддинга - Тень Чернобыля, Чистое небо или Зов Припяти.
1. Какая стоит игра, с каким патчем? 2. Какой мод, версия мода? 3. Что правили своими ручками? 4. Конфиг компа. 5. Лог вылета и последние 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 - содержит секции конфигов уникального оружия и костюмов.
У кого есть желание, создать FAQ по основным вопросам моддинга - обращаемся в ЛС.
Метод add_call создаёт два коллбека, функции для которых являются параметрами самого метода:
Код
level.add_call (condition, action)
Функция condition будет вызываться до тех пор пока будет возвращать false/nil. Как только вернёт true - будет вызвана функция action. Самый тривиальный пример использования - таймер по истечению которого выполняется какое-либо действие:
Код
--# Взводим таймер на тридцать секунд. local timer = 30000 local timeNow = time_global() + timer --# Проверяем время. local function ConditionCall () if timeNow > time_global() then return true end return false end --# Действие по окончании таймера. local function ActionCall () news_manager.send_tip(db.actor, "Time is out!") end --# Ставим коллбек. level.add_call(ConditionCall, ActionCall)
Ничего естественно само не сохраняется, поэтому об этом нужно заботится самому.
--[[--------------------------------------------------------------------------------------------------------- File : ins_timer.script Author of assembly : ins33 Start : Добавить в секцию фонаря "[device_torch]" script_binding = name_script.init -]]----------------------------------------------------------------------------------------------------------
time_a local rest_time_a = 0 local minute = 60*1000 -- игровая минута local hour = minute*6 -- игровой час
function update() -- в bind_stalker.script в update(delta) добавь name_script.update() this.timer_start() -- Таймер this.hud_timer() -- Вывод секундомера на худ. end
function timer() -- в диалог добавляем <action>name_script.name_function</action> time_a = time_global() + hour*2 -- взводим на 2 часа db.actor:give_info_portion("get_gun1") -- Выдаём поршень работы таймера. end
function timer_start() -- на update(delta) if has_alife_info("name_infoporticion") then -- проверяем условие работы таймера if time_a == nil then -- если вдруг таймер обнулился (перезагрузка) if rest_time_a ~= 0 then -- и остался остаток (он будет только если используешь тот скрипт) то time_a = time_global() + rest_time_a -- вычисляем остаток времени end else -- или rest_time_a = time_a - time_global() -- остаток = разнице if time_a < time_global() then -- если пора "вставать" db.actor:disable_info_portion("name_infoporticion") -- забираем поршень, что-бы остановить таймер. db.actor:give_info_portion("get_gun") -- выдаём поршень, который проверяется в диалоге. news_manager.send_tip(db.actor, "%c[255,0,255,0]Бармен.\\n%c[default]Зайди ко мне, поговорить надо.", 0, "trader", 5000) -- отправим смс. Если надо. time_a = nil -- обнуляем rest_time_a = 0 -- обнуляем end end end end
-- выводим значение таймера в обратном отсчете на худ function hud_timer() --/ вызывается из ':update' сталкер-биндера local hud = get_hud() local st if time_a then st = hud:GetCustomStatic("hud_timer") if st==nil then hud:AddCustomStatic("hud_timer", true) st = hud:GetCustomStatic("hud_timer") end if rest_time_a~=nil then -- Остался ли остаток local hours = math.floor(rest_time_a/3600000) -- показываем часы local minutes = math.floor(rest_time_a/60000 - hours*60) -- показываем минуты local seconds = math.floor(rest_time_a/1000 - hours*3600 - minutes*60) -- показываем секунды local text = string.format("%02d:%02d:%02d",hours,minutes,seconds) -- формат вывода st:wnd():SetTextST(text) end else if hud:GetCustomStatic("hud_timer")~=nil then hud:RemoveCustomStatic("hud_timer") end end end
function init(obj) local torch = torch_binder(obj) obj:bind_object(torch) end
class "torch_binder" (object_binder) function torch_binder:__init(obj) super(obj) end
function torch_binder:reload(section) object_binder.reload(self, section) end
function torch_binder:reinit() object_binder.reinit(self) end
function torch_binder:update(delta) object_binder.update(self, delta) update() end
function torch_binder:net_spawn(data) return object_binder.net_spawn(self, data) end
function torch_binder:net_destroy() object_binder.net_destroy(self) end
function torch_binder:net_save_relevant() return true end
--// сохранение и загрузка табличных и прочих данных - так как фонарик всегда в онлайне - очень удобно использовать
function torch_binder:save(p) -- тут сохраняем значение object_binder.save(self, p) p:w_u32(rest_time_a) -- остаток p:w_u32(this.SaveBackTimer()) -- походу тут хранится end
function torch_binder:load® -- отсюда загружаем object_binder.load(self, r) rest_time_a = r:r_u32() -- остаток this.LoadBackTimer(r:r_u32()) -- соответственно загружается end
Arist, Попробуй передать в несуществующий тайник, если не будет вылета, то перестраховка, которая скажет, что не туда спавнишь. Если будет, то смотри, что лог напишет. Точнее, упомянет ли он имя несуществующего тайника.
Добавлено (17.04.2014, 00:10) --------------------------------------------- Сейчас у себя проверю.
function spawn_object_in(actor, obj, p) local spawn_sect = p[1] local target_name = p[2] local box = alife():object(target_name) if spawn_sect ~= nil and target_name ~= nil and box ~=nil then local obj = alife():create(spawn_sect,vector(),0,0,box.id) end end
В рестриктор тоже сработало(заспавнил сталкера и аптечку) [logic] active = sr_idle
[sr_idle] on_info = {+test_info} nil %=spawn_obj_in_zone(agr_stalker_veteran:esc_test_restrictor) =spawn_obj_in_zone(medkit:esc_test_restrictor)% В xr_effects.script
Код
function spawn_obj_in_zone(actor, obj, p) local spawn_sect = p[1] local zone_name = p[2] local zone = db.zone_by_name[zone_name] if spawn_sect ~= nil and zone_name ~= nil and zone ~= nil then local spawned_obj = alife():create( spawn_sect,zone:position(),zone:level_vertex_id(),zone:game_vertex_id()) end end
Надо через диалог попробовать.
Сообщение отредактировал Arist - Четверг, 17.04.2014, 00:38
ins33, а как правильно повесить timer_start? я повесил
Код
timer_start.update(delta)
и получил
Код
Expression : fatal error Function : CScriptEngine::lua_error File : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp Line : 73 Description : <no expression> Arguments : LUA error: ...:\s.t.a.l.k.e.r\gamedata\scripts\bind_stalker.script:246: attempt to index global 'timer_start' (a nil value)
Но у меня правленый скрипт для вывода в лог инфы по логике. С стандартным этой строки Cannot find saved game error: there is no such object bla_bla не будет.
Sanjaaa, В том скрипте было 2 опечатки, ты их исправил? Лог говорит, что в скрипте timer_start есть ошибка. Проверь его script Syntax Checker.exe П.С. ты исправил torch_binder:load® на torch_binder:load(_r_) только без _! Сайт р в скобках отображает, как ®
А как ты в диалоге собираешься medkit:esc_test_restrictor передать? А для спавн в тайник или нпс, я использую эту ф-ию:
Код
-- =give_items_nps(item:sid) function give_items_nps(actor, npc, p) local item = p and p[1] local to_obj = level_object_by_sid(p[2]) alife():create(item, to_obj:position(), to_obj:level_vertex_id(), to_obj:game_vertex_id(), to_obj:id()) end
Но тут передаётся sid, что не всегда удобно! Хотя можно использовать
Код
-- =name(name) function name(actor, npc, p) local obj = p[1] for a=10,65635,1 do local npc=level.object_by_id(a) if npc and string.find(npc:name(),obj) then *
и передавать имя.
Помогите разобраться с оверрайдами в секции [mob_home] mob_home.script:
---------------------------------------------------------------------------------------------------- -- Mob Home ---------------------------------------------------------------------------------------------------- -- Разработчик: Jim ----------------------------------------------------------------------------------------------------
local def_min_radius = 20 local def_max_radius = 40
class "mob_home"
---------------------------------------------------------------------------------------------------- -- CONSTRUCTION SCHEME ---------------------------------------------------------------------------------------------------- function mob_home:__init(obj, storage) self.object = obj self.st = storage end
---------------------------------------------------------------------------------------------------- -- RESET SCHEME ---------------------------------------------------------------------------------------------------- function mob_home:reset_scheme() --[[ Добавлено: Haron Описание: Теперь можно задавать радиусы home_min_radius и home_max_radius во флагах пути path_home. Для этого введены флаги minr, maxr. Они должны быть прописаны в первой точке пути. У радиусов заданых в секции приоритет больший чем для тех что заданы во флагах, т.е. если задано и там и там, то берутся значения из секции (сделано для обратной совместимости). --]] local minr, maxr = def_min_radius, def_max_radius local ptr = patrol(self.st.home) local path_info = utils.parse_waypoint_data(self.st.home, ptr:flags(0), ptr:name(0)) local r = 0
if self.st.home_min_radius then minr = self.st.home_min_radius else r = path_info.minr if r then r = tonumber® if r then minr = r end end end
if self.st.home_max_radius then maxr = self.st.home_max_radius else r = path_info.maxr if r then r = tonumber® if r then maxr = r end end end
-- check min and max radius if minr > maxr then _G.abort("Mob_Home : Home Min Radius MUST be < Max Radius. Got: min radius = %d, max radius = %d.", minr, maxr) end
self.object:set_home(self.st.home, minr, maxr, self.st.aggressive) end
if xr_logic.try_switch_to_another_section(self.object, self.st, db.actor) then return end
if mob_alife_mgr.alife_control(self.object, db.actor, self.st.alife_mode) then-- Добавил return-- Добавил end-- Добавил end
function mob_home:deactivate() self.object:remove_home() end
---------------------------------------------------------------------------------------------------- -- ADD_TO_BINDER ---------------------------------------------------------------------------------------------------- function add_to_binder(npc, ini, scheme, section, storage) printf("DEBUG: add_to_binder: npc:name()='%s', scheme='%s', section='%s'", npc:name(), scheme, section)
local new_action = mob_home(npc, storage)
-- Зарегистрировать все actions, в которых должен быть вызван метод reset_scheme при изменении настроек схемы: xr_logic.subscribe_action_for_events(npc, storage, new_action) end
---------------------------------------------------------------------------------------------------- -- SET_SCHEME ---------------------------------------------------------------------------------------------------- function set_scheme(npc, ini, scheme, section, gulag_name) local storage = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)
Проверял все 4 оверрайда в разных вариантах\сочетаниях, и не один не сработал. ХЕЛП!!!
Добавлено (17.04.2014, 01:21) --------------------------------------------- Sanjaaa, На тот момент у меня был только один таймер, и писать доп ф-ию, которая будет запускать остальные, не было смысла. Если обратишь внимание, то ф-ия update запускает timer_start() и hud_timer(), а сама она висит на update(delta).
ЦитатаSanjaaa ()
А "r" обязательно маленькую,а то я большую поставил
ни когда не задавался этим вопросом, думаю это не критично. Сам всегда пишу маленькую. П.С. комментарии исправил.
function spawn_object(actor, obj, p) local spawn_sect = p[1] local path_name = p[2] if level.patrol_path_exists(path_name) and spawn_sect ~= nil and path_name ~= nil then local ptr = patrol(path_name) local se_obj = alife():create(spawn_sect,ptr:point(),ptr:level_vertex_id(0),ptr:game_vertex_id(0)) end end
ни когда не задавался этим вопросом, думаю это не критично.
Критично. Lua чувствителен к регистру и для него Value и value - разные переменные.
Цитатаins33 ()
Проверял все 4 оверрайда в разных вариантах\сочетаниях, и не один не сработал.
При выставленном значении actor_friendly плоть нападала на ГГ? Попробуй подсунуть вместо mob_home - mob_walker, с тем же actor_friendly = true, если будет нападать, то причина в чём-то другом.
ins33, ну я вообще хз что такое. прописал в бинде апдейт без дельты, проверил на ошибки скрипт, ошибок нету! а вылетает серавно
Код
Expression : fatal error Function : CScriptEngine::lua_error File : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp Line : 73 Description : <no expression> Arguments : LUA error: ...:\s.t.a.l.k.e.r\gamedata\scripts\bind_stalker.script:246: attempt to index global 'timer_start' (a nil value)
Сообщение отредактировал Sanjaaa - Четверг, 17.04.2014, 08:58