Багато хто з модоробів, які створюють апгрейди для зброї, та й у цілому нову зброю (зокрема поліпшену), стикаються з проблемою переповнення кількості байтів інформації в секції файлу mp_ranks.ltx. Я також не виключення, при створенні скрипта апгрейду зброї все йшло чудово, тест також пройшов на 12, але коли апгрейд став підходити до кінця, то є коли необхідно було прописати всі апгрейди зброї в ранги, відбувся виліт. А прописав усього апгрейд тільки для однієї зброї. Але з усілякої проблеми можна знайти логічний вихід. Пропоную ось цей.
Алгоритм
Для початку необхідно продумати, що і як, коли і за яких умов працюватиме скрипт. Так як ми його розробляли для нашого мода, то приклади і всі складові буде повністю або частково взято з модифікації.
1. Об'єкт викидається.
2. Підбирається НПС.
І якщо зброя не прописана у рангах, то виліт. Щоб НПС підбирав ту зброю, яка прописана в рангах, потрібно видалити непрописану зброю, що викидається, і спанити на її місці точно таку ж, але прописану в рангах, причому візуал і основні характеристики повинні відповідати тій вибраній зброї (щоб не порушити ігровий процес і симуляцію). Такий спосіб можна досягти шляхом зняття ні-пакета з зброї, що викидається, і запису її на таку ж зброю але не апгрейдну. Для початку відстежимо саме викидання. Відкриємо bind_stalker.script і напишемо функцію з умовою, за якої буде видалятися:
local sip_b = 1 -– переменная, при определении которой будет -- производиться действие, по дефолту 1 function sip_bool(flag) –- функция, которая запускается сторонней функцией -- из другого скрипта, дабы не совершить вылета, аргумент = число if flag == 1 then sip_b = 1 else sip_b = 0 end end
Операція присвоєння здійснюється відповідно, щоб не сплутати. Шукаємо:
function actor_binder:on_item_drop (obj) level_tasks.proceed(self.object) end
Ця функція відстежує викидання чогось із інвентарю РР. Змінимо так:
function actor_binder:on_item_drop (obj) level_tasks.proceed(self.object) if sip_b == 1 then project_sip.delete_weapon(obj) end end
Що дозволить обійти той момент запису ні-пакета в неіснуючий об'єкт. Далі створюємо скрипт project_sip.script і пишемо до нього наступне:
local sects = {} local tab_id = {} local tab_old_id = {} local now_wpn_id local sect_old local sect –- присвоим позже оригинальную секцию оружия, -- которая в последующем будет использована для спавна local orig_sect –- переменной будет присвоена секция оружия local count = 0 local num local new_id local name –- будет присвоено оригинальное название оружия function delete_weapon(weapon) -– функция удаления оружия, аргумент сам объект --таблица оружия, которое прописано в рангах local wpn_tab = {"wpn_abakan","wpn_rpg7","wpn_ak74","wpn_fn2000","wpn_g36","wpn_groza","wpn_l85", "wpn_lr300","wpn_mp5","wpn_rpg7","wpn_sig550","wpn_val","wpn_spas12","wpn_toz34","wpn_wincheaster1300", "wpn_svd","wpn_svu","wpn_vintorez","wpn_beretta","wpn_colt1911","wpn_desert_eagle", "wpn_fort","wpn_hpsa","wpn_pb","wpn_pm","wpn_sig220","wpn_walther"} local wpn = weapon:section() orig_sect = wpn local pos_act = db.actor:position() pos_act.x = pos_act.x + 0.3 –- оружие будет спавниться не в инвентарь к ГГ, -- а в 30см от него, ибо при спавне в инвентарь нет-пакет в оружие не записывается. -- ниже проверяем, что оружие действительно апгрейдное (в данном случае идет проверка -- не только на то что оружие апгрейдное, но еще и на то, что оружие имеет секцию смены визуала) if string.find(wpn,"list") or string.find(wpn,"prugina") or string.find(wpn,"tormoz") or string.find(wpn,"sv1") or string.find(wpn,"sv2") or string.find(wpn,"sv3") or string.find(wpn,"sv4") then for k = 1, #wpn_tab do –- запускаем цикл на выявление оригинала оружия (прописанного в рангах) name = k if string.find(wpn,wpn_tab[name]) then sect = wpn_tab[name] break –- если условие выполняется, то преждевременно останавливаем выполнение цикла end end -- ниже происходит запись в таблицы данных о секциях table.insert(sects,orig_sect) table.insert(tab_old_id,weapon:id()) -- производим снятие нет-пакета, для этого подготовливаем все условия для этого local n_obj = alife():object(weapon:id()) –- определяем объект local func_net = net_pack_sip.wpn_d_r(n_obj) –- снимаем нет-пакет объекта alife():release(n_obj,true) –- присвоим, но не заспавним объект local sobj = alife():create(sect,pos_act,db.actor:level_vertex_id(),db.actor:game_vertex_id()) if sobj then table.insert(tab_id,sobj.id) –- запишем id оружия в таблицу для дальнейшей работы с ним net_pack_sip.wpn_d_w(func_net,sobj) –- запишем на это оружие весь нет-пакет удаленного оружия end end return sobj –- заспавним оружие end
Ось, практично, можна сказати що все, проте коли ГГ візьме цю зброю, то вона вже не буде такою, якою вона була до викидання!!! Виправимо цю ситуацію. У біндері знайдемо наступний код:
function actor_binder:on_item_take (obj) level_tasks.proceed(self.object) end
та змінимо так:
function actor_binder:on_item_take (obj) level_tasks.proceed(self.object) project_sip.spawn_old_wpn(obj) end
Ця функція відстежує момент взяття ГГ будь-якого об'єкта, аргументує сам об'єкт. У project_sip.script пропишемо наступний код:
function spawn_old_wpn(obj) for k = 1, #tab_id do –- запускаем цикл на вычисление идетификатора оружия, -- которое было создано в момент удаления апгрейдного оружия (секция которого была записана ранее) if obj:id() == tab_id[k] then num = k now_wpn_id = tab_id[num] -- получаем id объекта sect_old = sects[num] –- получаем секцию удаленного апгрейдного оружия spawn_del_weap(sect_old,now_wpn_id) –- запускаем функцию снятия и записи нет-пакета в новое оружие, -- дабы не нарушить симуляцию break end end end -- прототип данной функции не требует комментария, ибо расписывался ранее function spawn_del_weap(sect_old,now_wpn_id) local pos_act = db.actor:position() pos_act.x = pos_act.x + 0.3 local n_obj = alife():object(now_wpn_id) local func_net = net_pack_sip.wpn_d_r(n_obj) alife():release(n_obj,true) local sobj = alife():create(sect_old,pos_act,db.actor:level_vertex_id(),db.actor:game_vertex_id()) if sobj then new_id = sobj.id – записываем id оружия для перевода его к ГГ net_pack_sip.wpn_d_w(func_net,sobj) end return sobj end function transfer_new_wpn() –- данная функция предназначена для перевода нового заспавненго оружия (апгрейдного к ГГ) if new_id ~= nil then local wpn = level.object_by_id(new_id) if wpn then db.actor:transfer_item(wpn,db.actor) new_id = nil end else return end end
Далі в біндері знайдемо:
function actor_binder:update(delta) object_binder.update(self, delta)
та нижче напишемо:
project_sip.transfer_new_wpn() – для перевода оружия к ГГ
скрипт net_pack_sip.script, у якому напишемо наступний код:
function wpn_d_r(sobj) local sv_sip = net_packet() sobj:STATE_Write(sv_sip) local size = sv_sip:w_tell() sv_sip:r_seek(0) local tab_config = {object_pack = {},visual_pack = {},item_pack = {},item_wpn_packet = {}} local function up_vis_pack(visual_pack,sv_sip,size) visual_pack.visual_name = sv_sip:r_stringZ() visual_pack.vsu8u1 = sv_sip:r_u8() return visual_pack end tab_config.object_pack.gvid = sv_sip:r_u16() tab_config.object_pack.obf32u1 = sv_sip:r_float() tab_config.object_pack.obs32u2 = sv_sip:r_s32() tab_config.object_pack.lvid = sv_sip:r_s32() tab_config.object_pack.oflags = sv_sip:r_s32() tab_config.object_pack.custom = sv_sip:r_stringZ() tab_config.object_pack.sid = sv_sip:r_s32() tab_config.object_pack.obs32u3 = sv_sip:r_s32() up_vis_pack(tab_config.visual_pack,sv_sip,size) tab_config.item_pack.condition = sv_sip:r_float() tab_config.item_wpn_packet.ammo_current = sv_sip:r_u16() tab_config.item_wpn_packet.ammo_elapsed = sv_sip:r_u16() tab_config.item_wpn_packet.weapon_state = sv_sip:r_u8() tab_config.item_wpn_packet.addon_flags = sv_sip:r_u8() tab_config.item_wpn_packet.ammo_type = sv_sip:r_u8() return tab_config end function wpn_d_w(tab_config,sobj) local sv_sip = net_packet() local function vis_pack_rd(visual_pack,sv_sip) sv_sip:w_stringZ(visual_pack.visual_name) sv_sip:w_u8(visual_pack.vsu8u1) return visual_pack end sv_sip:w_u16(tab_config.object_pack.gvid) sv_sip:w_float(tab_config.object_pack.obf32u1) sv_sip:w_s32(tab_config.object_pack.obs32u2) sv_sip:w_s32(tab_config.object_pack.lvid) sv_sip:w_s32(tab_config.object_pack.oflags) sv_sip:w_stringZ(tab_config.object_pack.custom) sv_sip:w_s32(tab_config.object_pack.sid) sv_sip:w_s32(tab_config.object_pack.obs32u3) vis_pack_rd(tab_config.visual_pack,sv_sip) sv_sip:w_float(tab_config.item_pack.condition) sv_sip:w_u16(tab_config.item_wpn_packet.ammo_current) sv_sip:w_u16(tab_config.item_wpn_packet.ammo_elapsed) sv_sip:w_u8(tab_config.item_wpn_packet.weapon_state) sv_sip:w_u8(tab_config.item_wpn_packet.addon_flags) sv_sip:w_u8(tab_config.item_wpn_packet.ammo_type) sv_sip:w_u16(tab_config.object_pack.gvid) sv_sip:w_float(tab_config.object_pack.obf32u1) sv_sip:w_s32(tab_config.object_pack.obs32u2) sv_sip:w_s32(tab_config.object_pack.lvid) sv_sip:w_s32(tab_config.object_pack.oflags) sv_sip:w_stringZ(tab_config.object_pack.custom) sv_sip:w_s32(tab_config.object_pack.sid) sv_sip:w_s32(tab_config.object_pack.obs32u3) local size = sv_sip:w_tell() sv_sip:r_seek(0) sobj:STATE_Read(sv_sip,size) end