Для начала необходимо продумать, что и как, когда и при каких условиях будет работать скрипт. Так как мы его разрабатывали для нашего мода, то примеры и все составляющие будут полностью либо частично взяты из модификации.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 Работа с нет-пакетами будет описана в отдельной статье, объясню лишь общий смысл предназначения нет-пакета. Он предназначен для хранения состояния объекта и его характеристик, и по сути своей является буфером обмена, в котором и хранится вся эта информация, в последующем действии идет запись по определенным таблицам каждого вида характеристик. Во второй функции происходит запись того снятого состояния объекта к новосозданному. Эта операция напоминает алгоритм спавна all.spawn и неспроста! Ибо при статистичном спавне через скрипт объекту также присваивается состояние, которое записано как дефолтовое, а спавн через нет-пакет предусматривает широкий спектр выбора характеристик спавненного оружия что в положительную сторону влияет на симуляцию.Ну вот в общем-то и все, теперь объясню, почему этот метод рекрита работает на 99%. Потому что на выполнение этих всех процессов требуется время, сам биндер запускается с периодом примерно 0,5 сек. (точно не помню), значит, чтобы отследить либо выбрасывание оружия, либо наоборот, его взятие нужен один период биндера, далее также необходим второй период для перевода нового заспавненного оружия к ГГ, итого не для выполнения всех этих действий требуется как минимум 0,8 сек. Почему не переводится при первом периоде биндера, мне так и не удалось выяснить, но факт есть факт, соответственно, если подойти вплотную к НПС и выбросить оружие, то произойдет вылет, если же произвести выбрасывание на некотором расстоянии, к примеру на 10 см, то вылета не будет. Нагрузка на оперативную память незначительна, так что можно смело использовать.В планах совершенствование метода рекрита и доведение его работоспособности до 99,9%.
Byurrer, spark95
P.S. - Если что то не работает (при переносе с сайта stalkerin.gameru.net/wiki могли потеряться пробелы) идем на эту страницу
|