convert_npc={}
local stpk=net_packet()
local uppk=net_packet()

function get_ammo_size(obj)
 local se_obj=alife():object(obj:id())
 stpk:w_begin(0)
 se_obj:STATE_Write(stpk)
 stpk:r_seek(stpk:w_tell()-2)
 return stpk:r_s16()
end

function read_ammo(packet)
 local st={}
 st.game_vertex_id=packet:r_u16()
 st.distance=packet:r_float()
 st.direct_control=packet:r_s32()
 st.level_vertex_id=packet:r_s32()
 st.object_flags=packet:r_s32()
 st.custom_data=packet:r_stringZ()
 st.story_id=packet:r_s32()
 st.spawn_story_id=packet:r_s32()
 st.visual_name=packet:r_stringZ()
 st.visual_flags=packet:r_u8()
 st.condition=packet:r_float()
 st.ammo_left=packet:r_u16()
 return st
end

function write_ammo(packet,st)
 packet:w_u16(st.game_vertex_id)
 packet:w_float(st.distance)
 packet:w_s32(st.direct_control)
 packet:w_s32(st.level_vertex_id)
 packet:w_s32(st.object_flags)
 packet:w_stringZ(st.custom_data)
 packet:w_s32(st.story_id)
 packet:w_s32(st.spawn_story_id)
 packet:w_stringZ(st.visual_name)
 packet:w_u8(st.visual_flags)
 packet:w_float(st.condition)
 packet:w_u16(st.ammo_left)
end

function get_restrictor_data(sobj)
 stpk:w_begin(0)
 uppk:w_begin(0)
 sobj:STATE_Write(stpk)
 sobj:UPDATE_Write(uppk)
 local size=stpk:w_tell()
 local size1=uppk:w_tell()
 stpk:r_seek(2)
 uppk:r_seek(2)
 local t={}
 parse_object_packet(t,stpk,uppk,size)
 parse_shape_packet(t,stpk,uppk,size)
 t.restrictor_type = stpk:r_u8()
 return t
end

function set_restrictor_data(t,sobj)
 stpk:w_begin(0)
 uppk:w_begin(0)
 fill_object_packet(t,stpk,uppk)
 fill_shape_packet(t,stpk,uppk)
 stpk:w_u8(t.restrictor_type)
 local size=stpk:w_tell()
 local size1=uppk:w_tell()
 stpk:r_seek(2)
 uppk:r_seek(2)
 sobj:STATE_Read(stpk,size)
 sobj:UPDATE_Read(uppk)
end

function parse_shape_packet(t,stpk,uppk)
 local shape_count=stpk:r_u8()
 t.shapes={}
 for i=1,shape_count do
  local shape_type=stpk:r_u8()
  t.shapes[i]={}
  t.shapes[i].shtype=shape_type
  if shape_type==0 then
   t.shapes[i].center=stpk:r_vec3()
   t.shapes[i].radius=stpk:r_float()
  else
   t.shapes[i].v1=stpk:r_vec3()
   t.shapes[i].v2=stpk:r_vec3()
   t.shapes[i].v3=stpk:r_vec3()
   t.shapes[i].offset=stpk:r_vec3()
  end
 end
end

function fill_shape_packet(t,stpk,updpk)
 stpk:w_u8(table.getn(t.shapes))
 for i=1,table.getn(t.shapes) do
  stpk:w_u8(t.shapes[i].shtype)
  if t.shapes[i].shtype==0 then
   stpk:w_vec3(t.shapes[i].center)
   stpk:w_float(t.shapes[i].radius)
  else
   stpk:w_vec3(t.shapes[i].v1)
   stpk:w_vec3(t.shapes[i].v2)
   stpk:w_vec3(t.shapes[i].v3)
   stpk:w_vec3(t.shapes[i].offset)
  end
 end
end

-- id на входе
function read_stalker_params_money(id)
 local sobj
 if type(id)=="number" then
  sobj=alife():object(id)
 else
  sobj=id
  id=sobj.id
 end
 if sobj then
  stpk:w_begin(0)
  sobj:STATE_Write(stpk) 
  stpk:r_seek(2)
  -- cse_alife_trader_abstract properties
  return stpk:r_s32()
 end
 return nil
end

-- id на входе
function read_stalker_params_character_name(id)
 local sobj
 if type(id) == "number" then
  sobj = alife():object(id)
 else
  sobj=id
  id=sobj.id
 end
 if sobj then
  stpk:w_begin(0)
  sobj:STATE_Write(stpk) 
  stpk:r_seek(2)
  -- cse_alife_trader_abstract properties
  stpk:r_s32()
  stpk:r_stringZ()
  stpk:r_s32()
  stpk:r_stringZ()
  stpk:r_s32()
  stpk:r_s32()
  stpk:r_s32()
  return stpk:r_stringZ()
 end
 return nil
end

-- id на входе
function read_stalker_params_visual(id)
 local sobj
 if type(id)=="number" then
  sobj=alife():object(id)
 else
  sobj=id
  id=sobj.id
 end
 if sobj then
  stpk:w_begin(0)
  sobj:STATE_Write(stpk) 
  stpk:r_seek(2)
  -- cse_alife_trader_abstract properties
  stpk:r_s32()
  stpk:r_stringZ()
  stpk:r_s32()
  stpk:r_stringZ()
  stpk:r_s32()
  stpk:r_s32()
  stpk:r_s32()
  stpk:r_stringZ()
  stpk:r_u8()
  stpk:r_u8()
  -- cse_alife_object properties
  stpk:r_u16()
  stpk:r_float()
  stpk:r_s32()
  stpk:r_s32()
  stpk:r_s32()
  stpk:r_stringZ()
  stpk:r_s32()
  stpk:r_s32()
  -- cse_visual
  return stpk:r_stringZ()
 end
 return nil
end

-- id на входе
function read_stalker_params(id)
 local sobj
 if type(id)=="number" then
  sobj=alife():object(id)
 else
  sobj = id
  id = sobj.id
 end
 if sobj then
  stpk:w_begin(0)
  uppk:w_begin(0)
  sobj:STATE_Write(stpk)
  sobj:UPDATE_Write(uppk)
  local size=stpk:w_tell()
  local size1=uppk:w_tell()
  stpk:r_seek(2)
  uppk:r_seek(2)
  local ret = {}
  -- cse_alife_trader_abstract properties
  ret.money=stpk:r_s32()
  ret.specific_character=stpk:r_stringZ()
  ret.trader_flags=stpk:r_s32()
  ret.character_profile=stpk:r_stringZ()
  ret.community_index=stpk:r_s32()
  ret.rank=stpk:r_s32()
  ret.reputation=stpk:r_s32()
  ret.character_name=stpk:r_stringZ()
  -- cse_alife_object properties
  ret.game_vertex_id=stpk:r_u16()
  ret.distance=stpk:r_float()
  ret.direct_control=stpk:r_s32()
  ret.level_vertex_id=stpk:r_s32()
  ret.object_flags=stpk:r_s32()
  ret.custom_data=stpk:r_stringZ()
  ret.story_id=stpk:r_s32()
  ret.spawn_story_id=stpk:r_s32()
  -- cse_visual
  ret.visual_name=stpk:r_stringZ()
  ret.upd_extra_data=read_extra(uppk,size)
  ret.extra_data=read_extra(stpk,size)
  return ret
 end
 return nil
end

-- таблица параметров и id на входе
function write_stalker_params(ret,id,convert)
 local sobj
 if type(id)=="number" then
  sobj = alife():object(id)
 else
  sobj=id
  id=sobj.id
 end
 if sobj then
  stpk:w_begin(0)
  uppk:w_begin(0)
  -- cse_alife_trader_abstract properties
  stpk:w_s32(ret.money)
  stpk:w_stringZ(ret.specific_character)
  stpk:w_s32(ret.trader_flags)
  stpk:w_stringZ(ret.character_profile)
  stpk:w_s32(ret.community_index)
  stpk:w_s32(ret.rank)
  stpk:w_s32(ret.reputation)
  stpk:w_stringZ(ret.character_name)
  -- cse_alife_object properties
  stpk:w_u16(ret.game_vertex_id)
  stpk:w_float(ret.distance)
  stpk:w_s32(ret.direct_control)
  stpk:w_s32(ret.level_vertex_id)
  stpk:w_s32(ret.object_flags)
  stpk:w_stringZ(ret.custom_data)
  stpk:w_s32(ret.story_id)
  stpk:w_s32(ret.spawn_story_id)
  -- cse_visual
  stpk:w_stringZ(ret.visual_name)
  write_extra(uppk,ret.upd_extra_data) 
  write_extra(stpk,ret.extra_data)
  local size=stpk:w_tell()
  stpk:r_seek(2)
  uppk:r_seek(2)
  sobj:STATE_Read(stpk,size)
  sobj:UPDATE_Read(uppk)
  local obj=level.object_by_id(id)
  if obj and convert then
   if convert==1 then
    convert_npc[id]={}
    convert_npc[id].flag="turn_off"	
   end
   if convert==2 then
    convert_npc[id]={}
    convert_npc[id].flag="turn_on"	
   end
  end
 end
end

-- id на входе
function read_stalker_params_restr(id)
  local sobj
  if type(id)=="number" then
   sobj=alife():object(id)
  else
   sobj=id

  end
  if sobj then
   stpk:w_begin(0)
   uppk:w_begin(0)
   sobj:STATE_Write(stpk)
   sobj:UPDATE_Write(uppk)
   local size=stpk:w_tell()
   local size1=uppk:w_tell()
   stpk:r_seek(2)
   uppk:r_seek(2)
   local tbl=parse_stalker_packet({},stpk,uppk,size,size1,sobj)
   return tbl
  end
  return nil
end

-- таблица параметров и id на входе
function write_stalker_params_restr(tbl,id,convert)
  local sobj
  if type(id)=="number" then
   sobj=alife():object(id)
  else
   sobj=id
  end
  if sobj then
   stpk:w_begin(0)
   uppk:w_begin(0)
   fill_stalker_packet(tbl,stpk,uppk,sobj)
   local size=stpk:w_tell()
   stpk:r_seek(2)
   uppk:r_seek(2)
   sobj:STATE_Read(stpk,size)
   sobj:UPDATE_Read(uppk)
 end
end

function read_outfit_params(id)
  local sobj
  if type(id)=="number" then
   sobj=alife():object(id)
  else
   sobj=id
   id=sobj.id
  end
  if sobj then
   stpk:w_begin(0)
   uppk:w_begin(0)
   sobj:STATE_Write(stpk)
   sobj:UPDATE_Write(uppk)
   local size=stpk:w_tell()
   local size1=uppk:w_tell()
   stpk:r_seek(2)
   uppk:r_seek(2)
   local tbl=parse_outfit_packet({},stpk,uppk,size,size1)
   return tbl
  end
  return nil
end

function write_outfit_params(tbl,id)
  local sobj
  if type(id)=="number" then
   sobj=alife():object(id)
  else
   sobj=id
   id=sobj.id
  end
  if sobj then
   stpk:w_begin(0)
   uppk:w_begin(0)
   fill_outfit_packet(tbl,stpk,uppk)
   local size=stpk:w_tell()
   stpk:r_seek(2)
   uppk:r_seek(2)
   sobj:STATE_Read(stpk,size)
   sobj:UPDATE_Read(uppk)
  end
end

function read_monster_params(id)
  local sobj
  if type(id)=="number" then
   sobj=alife():object(id)
  else
   sobj=id
   id=sobj.id
  end
  if sobj then
   stpk:w_begin(0)
   uppk:w_begin(0)
   sobj:STATE_Write(stpk)
   sobj:UPDATE_Write(uppk)
   local size=stpk:w_tell()
   local size1=uppk:w_tell()
   stpk:r_seek(2)
   uppk:r_seek(2)
   local tbl=parse_se_monster_packet({},stpk,uppk,size)
   return tbl
  end
  return nil
end

function write_monster_params(tbl,id)
  local sobj
  if type(id)=="number" then
   sobj=alife():object(id)
  else
   sobj=id
   id=sobj.id
  end
  if sobj then
   stpk:w_begin(0)
   uppk:w_begin(0)
   fill_se_monster_packet(tbl,stpk,uppk)
   local size=stpk:w_tell()
   stpk:r_seek(2)
   uppk:r_seek(2)
   sobj:STATE_Read(stpk,size)
   sobj:UPDATE_Read(uppk)
  end
end

function parse_outfit_packet(ret,stpk,updpk,size,size1)
 parse_dynamic_object_visual(ret,stpk,updpk)
 parse_item_packet(ret,stpk,updpk)
 ret.upd_condition=updpk:r_u8() 
 ret.upd_extra_data=read_extra(updpk,size1)
 ret.imm=stpk:r_u8()
 ret.pid=stpk:r_s32()
 ret.con=stpk:r_float()
 ret.extra_data=read_extra(stpk,size)
 return ret
end

function fill_outfit_packet(ret,stpk,updpk)
 fill_dynamic_object_visual(ret,stpk,updpk)
 fill_item_packet(ret,stpk,updpk)
 updpk:w_u8(ret.upd_condition)
 write_extra(updpk,ret.upd_extra_data)
 stpk:w_u8(ret.imm)
 stpk:w_s32(ret.pid)
 stpk:w_float(ret.con)
 write_extra(stpk,ret.extra_data)
end

function parse_item_packet(ret,stpk,updpk)
 ret.condition=stpk:r_float()
 ret.upgrades=readvu32stringZ(stpk)
 ret.upd_num_items=updpk:r_u8()
 ret.float_data_item_packet=read_float(updpk,19)
 ret.upd_ph_unknown=updpk:r_u8()
 return ret
end

function fill_item_packet(ret,stpk,updpk)
 stpk:w_float(ret.condition)
 writevu32stringZ(stpk,ret.upgrades)
 updpk:w_u8(ret.upd_num_items)
 write_float(updpk,ret.float_data_item_packet)
 updpk:w_u8(ret.upd_ph_unknown)
end

function parse_stalker_packet(ret,stpk,updpk,size,size1,sobj)
 parse_human_packet(ret,stpk,updpk)
 --[[
 parse_skeleton_packet(ret,stpk,updpk)
 ret.upd_start_dialog=updpk:r_stringZ()
 ret.upd_extra_data=read_extra(updpk,size1)
  local t
  local newver=false
  t = stpk:r_u8()
  newver=(t>99)
  if newver then
   t=t-100
  end
 if t==0 or t==1 or t==2 then
  ret.job_online=t
 else
  ret.job_online=3
  ret.job_online_condlist=stpk:r_stringZ()
 end
 if newver then
  ret.upgo=readvu32stringZ(stpk)
  ret.upgh=readvu32stringZ(stpk)
  ret.cono=stpk:r_float()
  ret.conh=stpk:r_float()
  ret.offmoney=stpk:r_s32()
  ret.bon=read_bon(stpk)
 end
 --]]
 ret.extra_data=read_extra(stpk,size)
 return ret
end

function fill_stalker_packet(ret,stpk,updpk,sobj)
 fill_human_packet(ret,stpk,updpk)
 --[[
 fill_skeleton_packet(ret,stpk,updpk)
 updpk:w_stringZ(ret.upd_start_dialog)
 write_extra(updpk,ret.upd_extra_data)
 local t = ret.job_online
 if t==0 or t==1 or t==2 then
  stpk:w_u8(t+100)
 else
  stpk:w_u8(103)
  stpk:w_stringZ(ret.job_online_condlist)
 end
 writevu32stringZ(stpk,ret.upgo)
 writevu32stringZ(stpk,ret.upgh)
 stpk:w_float(ret.cono)
 stpk:w_float(ret.conh)
 stpk:w_s32(ret.offmoney)
 write_bon(stpk,ret.bon)
 --]]
 write_extra(stpk,ret.extra_data)
end

function parse_human_packet(ret,stpk,updpk)
 parse_trader_packet(ret,stpk,updpk)
 parse_monster_packet(ret,stpk,updpk)
 ret.predicate5=readvu32u8(stpk)
 ret.predicate4=readvu32u8(stpk)  
 return ret
end

function fill_human_packet(ret,stpk,updpk)
 fill_trader_packet(ret,stpk,updpk)
 fill_monster_packet(ret,stpk,updpk)
 writevu32u8(stpk,ret.predicate5)
 writevu32u8(stpk,ret.predicate4)
end

function parse_skeleton_packet(ret,stpk,updpk)
 ret.skeleton_name=stpk:r_stringZ()
 ret.skeleton_flags=stpk:r_u8()
 ret.source_id=stpk:r_u16()
 if bit_and(ret.skeleton_flags,4) then
  ret.unk_n=readvu8u8(stpk)
  ret.unk_n1 = stpk:r_u16()
  ret.float_data_skeleton_packet=read_float(stpk,6)
  ret.unk_n4 = readvu16u64(stpk)
 end  
 return ret
end

function fill_skeleton_packet(ret,stpk,updpk)
 stpk:w_stringZ(ret.skeleton_name)
 stpk:w_u8(ret.skeleton_flags)
 stpk:w_u16(ret.source_id)
 if bit_and(ret.skeleton_flags,4) then
  writevu8u8(stpk,ret.unk_n)
  stpk:w_u16(ret.unk_n1)
  write_float(stpk,ret.float_data_skeleton_packet)
  writevu16u64(stpk,ret.unk_n4)
 end
end

function parse_trader_packet(ret,stpk,updpk)
 ret.money=stpk:r_s32()
 ret.specific_character=stpk:r_stringZ()
 ret.trader_flags=stpk:r_s32()
 ret.character_profile=stpk:r_stringZ()
 ret.community_index=stpk:r_s32()
 ret.rank=stpk:r_s32()
 ret.reputation=stpk:r_s32()
 ret.character_name=stpk:r_stringZ()  
 return ret
end

function fill_trader_packet(ret,stpk,updpk)
 stpk:w_s32(ret.money)
 stpk:w_stringZ(ret.specific_character)
 stpk:w_s32(ret.trader_flags)
 stpk:w_stringZ(ret.character_profile)
 stpk:w_s32(ret.community_index)
 stpk:w_s32(ret.rank)
 stpk:w_s32(ret.reputation)
 stpk:w_stringZ(ret.character_name)
end

function parse_monster_packet(ret,stpk,updpk)
 parse_creature_packet(ret,stpk,updpk)
 ret.base_out_restrictors=stpk:r_stringZ()
 ret.base_in_restrictors=stpk:r_stringZ()
 ret.smart_terrain_id=stpk:r_u16()
 ret.smart_terrain_task_active=stpk:r_u8()
 ret.upd_next_game_vertex_id=updpk:r_u16()
 ret.upd_prev_game_vertex_id=updpk:r_u16()
 ret.upd_distance_from_point=updpk:r_float()
 ret.upd_distance_to_point=updpk:r_float()
 return ret
end

function fill_monster_packet(ret,stpk,updpk)
 fill_creature_packet(ret,stpk,updpk)
 stpk:w_stringZ(ret.base_out_restrictors)
 stpk:w_stringZ(ret.base_in_restrictors)
 stpk:w_u16(ret.smart_terrain_id)
 stpk:w_u8(ret.smart_terrain_task_active)
 updpk:w_u16(ret.upd_next_game_vertex_id)
 updpk:w_u16(ret.upd_prev_game_vertex_id)
 updpk:w_float(ret.upd_distance_from_point)
 updpk:w_float(ret.upd_distance_to_point)
end

function parse_se_monster_packet(ret,stpk,updpk,size)
  parse_monster_packet(ret,stpk,updpk,size)
  ret.extra_data=read_extra(stpk,size)
  return ret
end

function fill_se_monster_packet(ret,stpk,updpk)
  fill_monster_packet(ret,stpk,updpk)
  write_extra(stpk,ret.extra_data)
end

function parse_creature_packet(ret,stpk,updpk)
 parse_dynamic_object_visual(ret,stpk,updpk)
 ret.g_team=stpk:r_u8()
 ret.g_squad=stpk:r_u8()
 ret.g_group=stpk:r_u8()
 ret.health=stpk:r_float()
 ret.dynamic_out_restrictions=readvu32u16(stpk)
 ret.dynamic_in_restrictions=readvu32u16(stpk)  
 ret.killer_id=stpk:r_u16()
 ret.game_death_time=readvu8u8(stpk)
 ret.upd_health=updpk:r_float()
 ret.upd_timestamp=updpk:r_s32()
 ret.upd_creature_flags=updpk:r_u8()
 ret.upd_position={}
 ret.upd_position.x=updpk:r_float()
 ret.upd_position.y=updpk:r_float()
 ret.upd_position.z=updpk:r_float()
 ret.upd_o_model=updpk:r_float()
 ret.upd_o_torso={}
 ret.upd_o_torso.x=updpk:r_float()
 ret.upd_o_torso.y=updpk:r_float()
 ret.upd_o_torso.z=updpk:r_float()
 ret.upd_g_team=updpk:r_u8()
 ret.upd_g_squad=updpk:r_u8()
 ret.upd_g_group=updpk:r_u8()  
 return ret
end

function fill_creature_packet(ret,stpk,updpk)
 fill_dynamic_object_visual(ret,stpk,updpk)
 stpk:w_u8(ret.g_team)
 stpk:w_u8(ret.g_squad)
 stpk:w_u8(ret.g_group)
 stpk:w_float(ret.health)
 writevu32u16(stpk,ret.dynamic_out_restrictions)
 writevu32u16(stpk,ret.dynamic_in_restrictions)  
 stpk:w_u16(ret.killer_id)
 writevu8u8(stpk,ret.game_death_time)
 updpk:w_float(ret.upd_health)
 updpk:w_s32(ret.upd_timestamp)
 updpk:w_u8(ret.upd_creature_flags)
 updpk:w_float(ret.upd_position.x)
 updpk:w_float(ret.upd_position.y)
 updpk:w_float(ret.upd_position.z)
 updpk:w_float(ret.upd_o_model)
 updpk:w_float(ret.upd_o_torso.x)
 updpk:w_float(ret.upd_o_torso.y)
 updpk:w_float(ret.upd_o_torso.z)
 updpk:w_u8(ret.upd_g_team)
 updpk:w_u8(ret.upd_g_squad)
 updpk:w_u8(ret.upd_g_group)
end

function parse_object_packet(ret,stpk,updpk)
 ret.game_vertex_id=stpk:r_u16()
 ret.distance=stpk:r_float()
 ret.direct_control=stpk:r_s32()
 ret.level_vertex_id=stpk:r_s32()
 ret.object_flags=stpk:r_s32()
 ret.custom_data=stpk:r_stringZ()
 ret.story_id=stpk:r_s32()
 ret.spawn_story_id=stpk:r_s32()
 return ret
end

function fill_object_packet(ret,stpk,updpk)
 stpk:w_u16(ret.game_vertex_id)
 stpk:w_float(ret.distance)
 stpk:w_s32(ret.direct_control)
 stpk:w_s32(ret.level_vertex_id)
 stpk:w_s32(ret.object_flags)
 stpk:w_stringZ(ret.custom_data)
 stpk:w_s32(ret.story_id)
 stpk:w_s32(ret.spawn_story_id)
end

function parse_visual_packet(ret,stpk,updpk)
 ret.visual_name=stpk:r_stringZ()
 ret.visual_flags=stpk:r_u8()
 return ret
end

function fill_visual_packet(ret,stpk,updpk)
 stpk:w_stringZ(ret.visual_name)
 stpk:w_u8(ret.visual_flags)
end

function parse_dynamic_object_visual(ret,stpk,updpk)
 parse_object_packet(ret,stpk,updpk)
 parse_visual_packet(ret,stpk,updpk)
 return ret
end

function fill_dynamic_object_visual(ret,stpk,updpk)
 fill_object_packet(ret,stpk,updpk)
 fill_visual_packet(ret,stpk,updpk)
end

function read_extra(packet,size)
 local v={}
 for i=packet:r_tell(),size-1,1 do
  table.insert(v,packet:r_u8())
 end
 return v
end

function read_float(packet,size)
 local v={}
 for i=1,size,1 do
  table.insert(v,packet:r_float())
 end
 return v
end

function readvu16u64(packet)
 local v={}
 local len=packet:r_u16()
 for i=1,len*8,1 do
  table.insert(v,packet:r_u8())
 end
 return v
end

function readvu32u8(packet)
 local v={}
 local len=packet:r_s32()
 for i=1,len,1 do
  table.insert(v,packet:r_u8())
 end
 return v
end

function readvu8u8(packet)
 local v={}
 for i=1,8,1 do
  table.insert(v,packet:r_u8())
 end
 return v
end

function read_bon(packet)
 local v={}
 for i=1,5,1 do
  table.insert(v,packet:r_u8())
 end
 return v
end

function readvu32u16(packet)
 local v={}
 local len=packet:r_s32()
 for i=1,len,1 do
 local readvu32u16_par = packet:r_u16()
  table.insert(v,readvu32u16_par)
 end
 return v
end

function readvu32stringZ(packet)
 local v={}
 local len=packet:r_s32()
 for i=1,len,1 do
  table.insert(v,packet:r_stringZ())
 end
 return v
end

function write_extra(pk,v)
 for i,k in ipairs(v) do
  pk:w_u8(k)
 end 
end

function write_float(pk,v)
 for i,k in ipairs(v) do
  pk:w_float(k)
 end 
end

function writevu16u64(pk,v)
 local len=#v
 pk:w_u16(len/8)
 for i=1,len,1 do
  pk:w_u8(v[i])
 end
end

function writevu32u8(pk,v)
 local len=#v
 pk:w_s32(len)
 for i=1,len,1 do
  pk:w_u8(v[i])
 end
end

function writevu8u8(pk,v)
 for i=1,8,1 do
  pk:w_u8(v[i])
 end
end

function write_bon(pk,v)
 if v==nil then v={} end
 for i=1,5,1 do
  pk:w_u8(v[i])
 end
end

function writevu32u16(pk,v)
 local len=#v
 pk:w_s32(len)
 for i=1,len,1 do
  pk:w_u16(v[i])
 end
end

function writevu32stringZ(pk,v)
 if v==nil then v={} end
 local len=#v
 pk:w_s32(len)
 for i=1,len,1 do
  pk:w_stringZ(v[i])
 end
end

function convert_npcs()
 for k,v in pairs(convert_npc) do
  local obj=level.object_by_id(k)
  local sobj=alife():object(k)
  if sobj then
   if obj==nil and v.flag=="turn_on" then
    if sobj.online ~= true then
     local t = read_stalker_params(sobj)
	 if t then
      if v.visnew then
       t.visual_name = v.visnew
      end
      write_stalker_params(t,sobj)
      sobj:switch_online()
     end
    end
    convert_npc[k].flag=false
   elseif obj~=nil and v.flag=="zombie_on" then
    convert_npc[k].charn=obj:character_name()
    convert_npc[k].sect=obj:section()
    convert_npc[k].pos=obj:position()
    convert_npc[k].lvid=obj:level_vertex_id()
    convert_npc[k].gvid=obj:game_vertex_id()
    obj:clear_animations()
    if sobj.alive and sobj:alive() then
     obj:stop_talk()
     xr_reach_task.PatrolManager():remove_npc(obj)
     local squad = get_object_squad(obj)
     if squad then
      squad:remove_npc(k)
     else
      alife():release(sobj,true)
     end
    else
     alife():release(sobj,true)
    end
    convert_npc[k].flag="released"
   elseif obj~=nil and v.flag=="turn_off" then
    if IsStalker(sobj) then
     obj:clear_animations()
     if sobj.alive and sobj:alive() then
      obj:stop_talk()
     end
    end
    sobj:switch_offline()
    convert_npc[k].flag="turn_on"
   elseif obj~=nil and v.flag=="transfer_outfit" then
    local npc = level.object_by_id(sobj.pid)
    if npc then
     obj:transfer_item(obj,npc)
    else
     alife():release(sobj, true)
    end
    convert_npc[k].flag=false
   elseif obj~=nil and v.flag=="transfer_helmet" then
    local npc = level.object_by_id(sobj.pid)
    if npc then
     obj:transfer_item(obj,npc)
    else
     alife():release(sobj, true)
    end
    convert_npc[k].flag=false
   elseif obj~=nil and v.flag==false then
    if IsStalker(sobj) then
     if ars_cop.change_outfit==true and sobj.alive and not sobj:alive() then
      local h = hit()
      h.draftsman = obj
      h.type = hit.strike
      h.direction = obj:direction()
      h:bone("bip01_spine")
      h.power = 1
      h.impulse = 200
      obj:hit(h)
     end
     if not v.charn then
      if ars_cop.change_outfit==true and obj:get_visual_name()~=v.visnew then
       convert_npc[k].flag="turn_off"
      end
     else
      ars_news.on_spawn(obj)
      local unreg_id=sobj:smart_terrain_id()    
      if unreg_id~=65535 and sobj.alive and sobj:alive() then      
       local unreg=alife():object(unreg_id)
       if unreg then        
        unreg:unregister_npc(sobj) 
       end
      end
     end
    end
    convert_npc[k]=nil
   end
  else
   if v.flag=="released" then
    local zombie=alife():create(v.sect.."_zombi",v.pos,v.lvid,v.gvid)
    if zombie then
     local t = read_stalker_params(zombie.id)
     if t then
      if v.charn then
       t.character_name=v.charn
      end
     end
     convert_npc[k]=nil
    end
   else
    convert_npc[k]=nil
   end
  end
 end
end

function get_addon_status(wpn,addon)
 if addon=="sc" then
  return wpn:weapon_scope_status()
 elseif addon=="sl" then
  return wpn:weapon_silencer_status()
 elseif addon=="gl" then
  return wpn:weapon_grenadelauncher_status()
 end
 return 0
end

local rep_mem={}

function get_addon_flag(wpn,with_int)
 local id,tg=wpn:id(),time_global()
 if tg==rep_mem.tg and rep_mem.id==id and rep_mem.wi==with_int then
  return rep_mem.fl
 else
  local flag=0
  if wpn:weapon_is_scope() then
   if with_int or get_addon_status(wpn,"sc")==2 then
    flag=1
   end
  end
  if wpn:weapon_is_silencer() then
   if with_int or get_addon_status(wpn,"sl")==2 then
    flag=flag+4
   end
  end
  if wpn:weapon_is_grenadelauncher() then
   if with_int or get_addon_status(wpn,"gl")==2 then
    flag=flag+2
   end
  end
  rep_mem={tg=tg,id=id,wi=with_int,fl=flag}
  return flag
 end
end

function addon_attached(wpn,addon,flag)
 local ft={
  sc={[1]=true,[3]=true,[5]=true,[7]=true},
  sl={[4]=true,[5]=true,[6]=true,[7]=true},
  gl={[2]=true,[3]=true,[6]=true,[7]=true}
 }
 if ft[addon] then
  return ft[addon][flag or get_addon_flag(wpn,true)] == true
 end
 return false
end

function get_visual(object)
 local obj
 if type(object)=="number" then
  obj=level.object_by_id(object)
 else
  obj=object
 end
 if obj then
  local vis=obj:get_visual_name()
  if vis~="" then
   vis=str_explode("\\",vis)
   vis=str_explode(".",vis[3])
   vis = vis[1]
   return vis
  end
 end
 return ""
end


-------------------------------------
function parse_ini_section_to_array(ini,section)
 local tmp=nil
 if ini and ini:section_exist(section) then
  tmp={}
  local result,id,value=nil,nil,nil
  for a=0,ini:line_count(section)-1 do
   result,id,value=ini:r_line(section,a,"","")
   if id~=nil and trim(id)~="" and trim(id)~=nil then
    tmp[trim(id)]=trim(value)
   end
  end
 end
 return tmp
end

function trim(s)
 return (string.gsub(s,"^%s*(.-)%s*$", "%1"))
end

function str_explode(div,str,clear)
 local t={}
 local cpt=string.find(str,div,1,true)
 if cpt then
  repeat
   if clear then
    table.insert(t,trim(string.sub(str,1,cpt-1)))
   else
    table.insert(t,string.sub(str,1,cpt-1))
   end
   str=string.sub(str,cpt+string.len(div))
   cpt=string.find(str,div,1,true)
  until cpt==nil
 end
 if clear then
  table.insert(t,trim(str))
 else
  table.insert(t,str)
 end
 return t
end

---------------------------------------------------------------------------------------
function pack_array_to_string(array)
 if not array then
  return "nil"
 end
 return string.char(1)..pack_new(array)
end

function unpack_array_from_string(str)
 if str==nil or str=="" or str=="nil" then return {} end
 if string.sub(str,1,1)~=string.char(1) then
  -- Старый формат упаковки
  return _parse(str)
 else
  -- новый формат упаковки тэгирован символом c кодом 1.
  return parse_new(string.sub(str,2,-1))
 end
end
function _assign(tbl,key,val)
 local key0=string.match(key,'"(.*)"')
 if key0 then
  tbl[key0]=val
 else
  tbl[key+0]=val
 end
end

local pack_type_num=1
local pack_type_string=2
local pack_type_bool=3
local pack_type_table=4
local pack_val_endtable=5

--[[
 Новый формат упаковки: 
 table ::= subtable
 subtable ::= keytype key valuetype ( value | subtable 0x5 )
 keytype ::= ( 0x1 | 0x2 | 0x3 | 0x4 )
 valuetype ::= ( 0x1 | 0x2 | 0x3 | 0x4 )
]]
function pack_new(tbl)
 local ret=""
 for k,v in pairs(tbl) do
  if type(k)=="number" then
   ret=ret..string.char(pack_type_num)..k
  elseif type(k)=="string" then
   ret=ret..string.char(pack_type_string)..k
  else
   abort("unsupported key type "..type(k))
  end
  if type(v)=="number" then
   ret=ret..string.char(pack_type_num)..v
  elseif type(v)=="string" then
   ret=ret..string.char(pack_type_string)..v
  elseif type(v)=="boolean" then
   ret=ret..string.char(pack_type_bool)..tostring(v)
  elseif type(v)=="table" then
   ret=ret..string.char(pack_type_table)..pack_new(v)..string.char(pack_val_endtable)
  end
 end
 return ret
end

function parse_new(str,idx)
 local ret={}
 idx=idx or 1
 while true do
  local key,value
  if idx>string.len(str) then
   return ret,idx
  end
  vtype,idx=get_byte(str,idx)
  if vtype==pack_type_num then
   key,idx=get_num(str,idx)
  elseif vtype==pack_type_string then
   key,idx=get_string(str,idx)
  elseif vtype==pack_val_endtable then
   return ret,idx
  else
   abort("unsupported key type "..tostring(vtype))
  end
  vtype,idx=get_byte(str,idx)
  if vtype==pack_type_num then
   value,idx=get_num(str,idx)
  elseif vtype==pack_type_string then
   value,idx=get_string(str,idx)
  elseif vtype==pack_type_bool then
   value,idx=get_bool(str,idx)
  elseif vtype==pack_type_table then
   value,idx=parse_new(str,idx)
  else
   abort("unsupported key type "..tostring(vtype))
  end
  ret[key]=value
 end
end

function _parse(str)
 local ret={}
 while str and str~="" do
  local i1,i2,key=string.find(str,'(.-)=>')
  str=string.sub(str,i2+1)
  i1,i2,val=string.find(str,'"(.-)"|')
  if val and i1==1 then
   -- строка
   _assign(ret,key,val)
  else
   i1,i2,val=string.find(str,'(%b{})|')
   if val and i1==1 then
    -- таблица
    _assign(ret,key,_parse(string.sub(val,2,-2)))
   else
    i1,i2,val=string.find(str,'(.-)|')
    -- число или булево значение
    if val=="true" then
     _assign(ret,key,true)
    elseif val=="false" then
     _assign(ret,key,false)
    else
     _assign(ret,key,val+0)
    end
   end
  end
  str=string.sub(str,i2+1)
 end
 return ret
end

function quotemeta(str)
 return (string.gsub(s, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%1"))
end

-- для правильного парсинга запрещены комментарии!!!
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.."\n["..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 get_byte(str,idx)
 return string.byte(string.sub(str,idx,idx)),idx+1
end

function get_string(str,idx)
 local idx1=string.len(str)+1
 for i=idx,string.len(str),1 do
  if string.byte(string.sub(str,i,i))<32 then
   idx1=i
   break
  end
 end
 return string.sub(str,idx,idx1-1),idx1
end

function get_num(str,idx)
 local st,idx1=get_string(str,idx)
 return st+0,idx1
end

function get_bool(str,idx)
 local st,idx1=get_string(str,idx)
 return st=="1",idx1
end

function dump_table(tbl)
 for k,v in pairs(tbl) do
  if type(v)=="table" then
   get_console():execute("load ~~~ "..tostring(k).." => ")
   dump_table(v)
  else
   str="load ~~~ "..tostring(k).." => "..tostring(v)
   if string.len(str)>200 then
    str=string.sub(str,1,200)
   end
   get_console():execute(str)
  end
 end
 get_console():execute("flush")
end

function angle_diff(a1, a2)
 local b1=a1:normalize()
 local b2=a2:normalize()
 local dotp=b1:dotproduct(b2)
 return utils.rad2deg(math.acos(dotp))
end

------------------------------------------------------------------------------------
function read_from_ini(ini,sec,lin,def,typ)
 if not ini then
  ini=system_ini()
 end
 if sec and lin and ini:section_exist(sec) and ini:line_exist(sec,lin) then
  if typ==0 then
   return ini:r_bool(sec,lin)
  elseif typ==1 then
   return ini:r_string(sec,lin)
  elseif typ==2 then
   return ini:r_string_wq(sec,lin)
  else
   return ini:r_float(sec,lin)
  end
 else
  return def
 end
end

------------------------------------------------------------------------------------
local aBufferedMessages={}

function mylog(sMsg,sMgr)
 if ars_cop.debug_mode==false then return end
 if sMsg==nil then return end
 if sMgr==nil then sMgr="Debug Info" end
 if db and db.actor then
  if aBufferedMessages then
   for k,v in pairs(aBufferedMessages) do
    db.actor:give_game_news(v[mgr],v[msg],"ui_inGame2_PD_Otmecheniy_zonoy",0,15000)
   end
   aBufferedMessages = nil
  end
  db.actor:give_game_news(sMgr,sMsg,"ui_inGame2_PD_Otmecheniy_zonoy",0,15000)
 else
  if aBufferedMessages then
   table.insert(aBufferedMessages,{mgr=sMgr,msg=sMsg})
  end
 end
 --if get_console() then
  --get_console():execute("load ~~~ "..string.sub(msg,1,200))
  --get_console():execute("flush")
 --end
end


function IsTrader(npc)
 local npc_id
 local com
 -- HACK
 if npc.m_story_id~=nil then
  npc_id=npc.id
  com=npc:community()
 else
  npc_id=npc:id()
  com=npc:character_community()
 end
 if com=="trader" then return true end
 local char_ini=xr_logic.get_customdata_or_ini_file(npc,"<customdata>")
 if char_ini and char_ini:section_exist("logic") and char_ini:line_exist("logic","trade") then
  return true
 end
 return false
end