Привет всем. Сегодня наш урок будет о том как сделать перепаковщик пачек патронов для Тени Чернобыля. Ведь когда играешь и собираешь куча патронов не получается сделать элементарную нычку какую либо, потому что патроны собранные с убитых вами сталкеров состоят из 3, 7, 10, 14 и т.д патронов в каждой пачке, а охота чтобы все эти патроны перепаковывались в одну или несколько нормальных пачек, вот поэтому я сегодня объясню как сделать такой же перепаковщик пачек патронов как и во многих других глобальных модах.
Действие первое Заходим в (gamedata/scripts) и создаём там новый скрипт с таким названием: dunin_ammo.script и вписываем в него вот это:
Код
local ammo = {} local inited = false local repack = false
-------- -- инициализация переменных, выполняется единожды -------- function init() local i, result, section, value -- отсюда возьмём размеры полных пачек local sys = system_ini() -- список патронов возьмём из "death_generic.ltx" local ini = ini_file("misc\\death_generic.ltx") local n = ini:line_count("ammo_sections") for i=0,n-1 do result, section, value = ini:r_line("ammo_sections",i,"","") ammo[section] = {} ammo[section].repack = false ammo[section].box = sys:r_u32(section, "box_size") end repack = false inited = true end
-------- -- вызывается при добавлении в инвентарь ГГ любых патрон -- obj - game_object добавляемой пачки -- здесь будем только ставить флажки о необходимости проверки, -- саму проверку и перепаковку сделаем в апдейте актёра, -- если перепаковку делать прям здесь, то будет глюк при загрузки и -- при взятии из нычки кучи патрон (взять всё) -------- function on_take(obj) if not inited then init() end
if ammo[section] ~= nil and section ~= nil and ammo[section].repack == false then if get_ammo_size(obj) < ammo[section].box then ammo[section].repack = true repack = true end end end
-------- -- вызывается из апдейта актёра -- проверяет наличие флажков и вызывает процедуру переупаковки -------- function on_update() if repack then local section, data for section, data in pairs(ammo) do if data.repack then repack_ammo(section, data.box) data.repack = false end end repack = false end end
-------- -- переупаковка патронов заданного типа -- section - строка, имя секции (тип патрон) -- box_size - колличество патрон в полной пачке -- сначало составляем список неполных пачек, затем -- удаляем их и создаём нужное колличество полных -------- function repack_ammo(section, box_size) --dbglog("repack_ammo('%s')", section) local s, t = enum_ammo(section, box_size) if (s > 0) and (table.getn(t) > 1) then --dbglog("repacking(magazins=%d, bullets=%d)", table.getn(t), s) local i, id local sim = alife() local pos = db.actor:position() local lvid = db.actor:level_vertex_id() local gvid = db.actor:game_vertex_id() local pid = db.actor:id()
for i, id in pairs(t) do sim:release(sim:object(id), true) end
while s >= box_size do sim:create_ammo(section, pos, lvid, gvid, pid, box_size) s = s - box_size end
if s > 0 then sim:create_ammo(section, pos, lvid, gvid, pid, s) end end end
-------- -- пробегаемся по инветарю ГГ и собираем инфу о неполных пачках -- section - строка, имя секции (тип патрон) -- box_size - колличество патрон в полной пачке -- возвращает сумарное колличество патрон в неполных пачках и массив id-шников этих пачек -------- function enum_ammo(section, box_size) local i, obj, size local s = 0 local t = {} for i=0, db.actor:object_count()-1 do obj = db.actor:object(i) if obj:section() == section then size = get_ammo_size(obj) if size < box_size then table.insert(t, obj:id()) s = s + size end end end return s, t end
-------- -- возвращает колличество патрон в пачке -- вроде подходящих функций нет, пришлось делать через net_packet -------- function get_ammo_size(obj) local se_obj = alife():object(obj:id()) local packet = net_packet() cse_alife_item_ammo.STATE_Write(se_obj, packet) --packet:r_advance(18) --packet:r_stringZ() --packet:r_advance(8) --packet:r_stringZ() --packet:r_advance(5) packet:r_seek(packet:w_tell() - 2) return packet:r_u16() end
Действие второе Теперь нам нужно вписать наш перепаковщик патронов в bind_stalker.script, открываем его и ищем там такую функцию:
Код
function actor_binder:on_item_take (obj)
и ставим внизу перед "end" вот такую функцию:
Код
dunin_ammo.on_take(obj)
Вот как должно у нас получиться:
Код
function actor_binder:on_item_take (obj) level_tasks.proceed(self.object) --game_stats.update_take_item (obj, self.object) dunin_ammo.on_take(obj) end