Advertisement
Faustle

bind_awr_0.2_fix

Dec 8th, 2017
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.72 KB | None | 0 0
  1. --[[
  2. Advanced Weapons Repair Mod 0.2 [Binder] by Faustle (2017)
  3. ]]--
  4.  
  5. local settings_list = {}
  6. local angles_t = {}
  7. local compare_name = {}
  8. local wpn_data = {}
  9. local wpn_details = {}
  10. local mech_list_key = {}
  11. local ini = ini_file("plugins\\awr_settings.ltx")
  12. local mesh_test_mode = ini:r_bool_ex("awr_mode","mesh_test_mode",false)
  13. local settings = alun_utils.collect_section(ini,"awr_settings")
  14. local mesh_list = alun_utils.collect_section(ini,"awr_angles")
  15. local weapons_list = alun_utils.collect_section(ini,"awr_weapon_list")
  16. local test_list = alun_utils.collect_section(ini,"awr_test")
  17. local scopes = alun_utils.collect_sections(system_ini(), {"addons_table"})
  18. local awr_sf = awr_shared_functions
  19.  
  20. for _, k in ipairs(settings) do
  21. settings_list[k] = ini:r_float_ex("awr_settings", k)
  22. end
  23.  
  24. for _, k in ipairs(mesh_list) do
  25. local t = alun_utils.parse_list(ini,"awr_angles", k)
  26. angles_t[k] = {}
  27. for _, v in ipairs(t) do
  28. table.insert(angles_t[k], v)
  29. end
  30. end
  31.  
  32. for key, val in pairs(angles_t) do
  33. mech_list_key[val[1]] = 0
  34. end
  35.  
  36. local test_wep = 1
  37. local wpn_condition, wpn, wpn_sect, delay, ui
  38.  
  39. local f_details = {
  40. tc_t = 'trigger_components',
  41. b_t = 'bolt',
  42. bc_t = 'bolt_carrier',
  43. gt_t = 'gas_tube',
  44. br_t = 'barrel'
  45. }
  46. local n_details = {
  47. 'barrel',
  48. 'trigger_components',
  49. 'bolt_carrier',
  50. 'bolt',
  51. 'gas_tube'
  52. }
  53.  
  54. function on_game_start()
  55. RegisterScriptCallback("physic_object_on_use_callback", physic_object_on_use_callback)
  56. RegisterScriptCallback("CUIActorMenu_OnItemFocusReceive", on_item_focus)
  57. RegisterScriptCallback("actor_on_first_update", actor_on_first_update)
  58. RegisterScriptCallback("npc_on_death_callback", npc_on_death_callback)
  59. end
  60.  
  61. function actor_on_first_update()
  62. local caller = debug.getinfo(1, "n").name
  63. awr_sf.dout(nil, caller, "Called on first update")
  64. for i=1, 65535 do
  65. local s_obj = alife():object(i)
  66. if s_obj then
  67. local name = s_obj:name()
  68. --// Если тиски заспавнены all.spawn - сохраняем их значения в store
  69. if string.match(name, '%w+%_awr%_tiski%_%d+') then
  70. awr_sf.dout(nil, caller, "%s is parent. Loading table angles_t[%s] from Store", name, name)
  71. angles_t[name] = awr_sf.l_v(name, angles_t[name])
  72.  
  73. --// Если тиски были заспавнены актором, находим изначальное имя, и загружаем в таблицу соответствующее значение
  74. elseif string.match(name, 'awr%_m%_wpn.*%d+') or string.match(name, '^awr%_tiski.*%d+') then
  75. local p_name = awr_sf.get_p_name(name)
  76. if p_name then
  77. awr_sf.dout(nil, caller, "%s is child. Loading parent table angles_t[%s] from Store", name, p_name)
  78. t = awr_sf.l_v(p_name, nil)
  79. if (t) then
  80. angles_t[p_name] = t
  81. end
  82. end
  83. elseif string.match(name, '_awr_lamp') then
  84. local lamp_obj = level.object_by_id(s_obj.id)
  85. if lamp_obj then
  86. if not (db.actor:has_info("awr_go_away")) then
  87. lamp_obj:get_hanging_lamp():turn_off()
  88. end
  89. end
  90. end
  91. end
  92. end
  93. for key, val in pairs(angles_t) do
  94. for _, v in ipairs(angles_t[key]) do
  95. if angles_t[key][3] == 'dead' then
  96. awr_sf.dout(nil, caller, "%s is dead. Enable lamp(s) which assigned for %s ", angles_t[key][1], key)
  97. awr_sf.LampOn(angles_t[key][1])
  98. end
  99. end
  100. end
  101.  
  102. compare_name = awr_sf.l_v('compare_name') or {}
  103. if compare_name then
  104. awr_sf.dout(nil, caller, "compare_name table loaded")
  105. else
  106. awr_sf.dout(nil, caller, "compare_name table is empty")
  107. end
  108.  
  109. wpn_data = awr_sf.l_v('wpn_data') or {}
  110. if wpn_data then
  111. awr_sf.dout(nil, caller, "wpn_data table loaded")
  112. else
  113. awr_sf.dout(nil, caller, "wpn_data table is empty")
  114. end
  115.  
  116. end
  117.  
  118. --// Доступ к тискам, с учетом возможной смерти механика
  119. function access(obj)
  120. local caller = debug.getinfo(1, "n").name
  121. local current_func = debug.getinfo(2, "n").name
  122.  
  123. if not (obj) then
  124. return
  125. end
  126.  
  127. local name = obj:name()
  128. local p_name = awr_sf.get_p_name(name)
  129.  
  130. awr_sf.dout(caller, current_func, "Request access for %s", name)
  131.  
  132. if angles_t[p_name] then
  133. if angles_t[p_name][3] == 'dead' then
  134. awr_sf.dout(caller, current_func, "Mechanic is dead. Full access.")
  135. return true
  136. end
  137. end
  138.  
  139. if db.actor:has_info("awr_go_away") then
  140. awr_sf.dout(caller, current_func, "Mechanic gave access.")
  141. return true
  142. end
  143.  
  144. local npc = get_story_object(angles_t[p_name][1])
  145. if npc then
  146. if npc:alive() then
  147. awr_sf.dout(caller, current_func, "Access not granted. NPC %s by id %s is alive.", angles_t[p_name][1], npc:id())
  148. else
  149. awr_sf.dout(caller, current_func, "![ERROR] NPC %s by id %s bugged, becase he is online and is not alive, but function OnDeath was not called.", angles_t[p_name][1], npc:id())
  150. end
  151. end
  152. end
  153.  
  154. --// Локальная функция для вызова через CreateTimeEvent. Также участвует в изменении cse_abstract части нет-пакета через callback (se_item.script:381) для изменения direction меша.
  155. local function create_call(n_obj,new,pos,lv,gv,yaw,wpn_fn,wpn_condition)
  156. local caller = 'create_call'
  157. local current_func = 'physic_object_on_use_callback'
  158.  
  159. local obj_name, p_name
  160.  
  161.  
  162. if (n_obj) then
  163. obj_name = n_obj:name()
  164. p_name = awr_sf.get_p_name(obj_name)
  165. if level.map_has_object_spot(n_obj.id, "ui_pda2_mechanic_location") ~= 0 then
  166. level.map_remove_object_spot(n_obj.id, "ui_pda2_mechanic_location")
  167. end
  168. alife():release(n_obj)
  169. end
  170.  
  171. local s_obj = alife():create(new, pos, lv, gv)
  172.  
  173. if s_obj then
  174. s_obj.repack = { ["direction"] = vector():set(0,tonumber(yaw),0) }
  175.  
  176. local c_name = {}
  177. local m_name = s_obj:name()
  178. if string.match(obj_name, '%w+%_awr%_tiski%_%d+') then
  179. awr_sf.dout(caller, current_func, "%s is parent name", m_name)
  180. c_name[obj_name] = m_name
  181. else
  182. c_name[p_name] = m_name
  183. end
  184.  
  185. --// Запись данных об оружии
  186. if string.match(m_name, 'awr_m_wpn') then
  187. awr_sf.dout(caller, current_func, "Save data of wpn %s with cond %s to store wpn_data[%s]", wpn_fn, wpn_condition, m_name)
  188. wpn_data[m_name] = {}
  189. wpn_data[m_name]['wpn_name'] = wpn_fn
  190. wpn_data[m_name]['condition'] = wpn_condition
  191. wpn_data[m_name]['time'] = alun_utils.CTime2table(game.get_game_time())
  192. awr_sf.s_v('wpn_data', wpn_data)
  193.  
  194. db.actor:give_info_portion(string.format("awr_%s_on_table", angles_t[p_name][1]))
  195. if db.actor:has_info(string.format("awr_%s_on_table", angles_t[p_name][1])) then
  196. awr_sf.dout(caller, current_func, "Get infoportion awr_%s_on_table", angles_t[p_name][1])
  197. end
  198. end
  199.  
  200. --// Изменение логики мешей
  201. local name = awr_sf.get_p_name(obj_name)
  202. local num = string.gsub(name, '(.*%_)(%d+)$', '%2')
  203. local lvl = string.gsub(level.name(), '(%w%d+%_)(.*)', '%2')
  204. awr_sf.set_logic(s_obj, lvl, num)
  205.  
  206. awr_sf.s_v('compare_name', c_name)
  207. end
  208.  
  209. if string.match(obj_name, 'awr_m_wpn') then
  210. awr_sf.d_v('wpn_data', obj_name)
  211. end
  212.  
  213. if db.actor:has_info(string.format("awr_%s_dead", angles_t[p_name][1])) then
  214. level.map_add_object_spot_ser(s_obj.id, "ui_pda2_mechanic_location", "st_mech_tiski")
  215. end
  216.  
  217. return true
  218. end
  219.  
  220. --// Функция-биндер при использовании меша тисков
  221. function physic_object_on_use_callback(_obj,who)
  222. local current_func = debug.getinfo(1, "n").name
  223. awr_sf.dout(nil, current_func, "Physic object on use.")
  224.  
  225. if not (mesh_test_mode) then
  226. if not (_obj) or not (string.match(_obj:name(), "awr")) then
  227. return
  228. end
  229.  
  230. local ch_obj = alife():object(_obj:id())
  231. local pos, lvID, gvID = _obj:position(), _obj:level_vertex_id(), _obj:game_vertex_id()
  232.  
  233. if (axr_main.config:r_value("mm_options","enable_extra_animations",1,false) == false) then
  234. delay = 0
  235. else
  236. delay = 100
  237. end
  238.  
  239. if access(_obj) and string.match(_obj:name(), "awr_tiski") and _obj:position():distance_to(db.actor:position()) < 1.5 then
  240. if (db.actor:active_slot() == 2 or db.actor:active_slot() == 3) then
  241. wpn = db.actor:active_item()
  242. local wpn_fn = wpn:name()
  243. wpn_sect = db.actor:active_item():section()
  244. for _, k in ipairs(weapons_list) do
  245. if wpn and (string.gsub(wpn_sect,k, "") == "") then
  246. awr_sf.dout(nil, caller, "WPN recognized and has not scopes")
  247. wpn_condition = wpn:condition()
  248. if (rx_utils.addon_attached(wpn,"sl") and not (string.match(wpn_sect, "wpn_val")) and not (string.match(wpn_sect, "wpn_vintorez"))) and not (string.match(wpn_sect, "wpn_vsk94")) or rx_utils.addon_attached(wpn,"gl") or wpn:get_ammo_in_magazine() > 0 then
  249. SetHudMsg(game.translate_string("st_unload"),3)
  250. awr_sf.dout(nil, caller, "WPN recognized, but has attached addons or magazine is not empty")
  251. else
  252. actor_effects.use_item("awr_repair_dummy")
  253.  
  254. if not awr_sf.IsWorn(wpn_sect) and not awr_sf.IsRusty(wpn_sect) then
  255. awr_sf.dout(nil, caller, "WPN quiality is good. Delay %s, new mesh name [awr_m_], angle %s, wpn name [%s], wpn condition %s", delay, wpn_sub, GetAngle(_obj), wpn_fn, wpn_condition)
  256. local wpn_sub = string.gsub(k, wpn_sect, wpn_sect)
  257. CreateTimeEvent("create_mesh","delay",delay,create_call,ch_obj,"awr_m_"..wpn_sub,pos,lvID,gvID,GetAngle(_obj),wpn_fn,wpn_condition)
  258. else
  259. awr_sf.dout(nil, caller, "WPN quiality is good. Delay %s, new mesh name [awr_m_], angle %s, wpn name [%s], wpn condition %s. Calling create_call()", delay, wpn_sub, GetAngle(_obj), wpn_fn, wpn_condition)
  260. CreateTimeEvent("create_mesh","delay",delay,create_call,ch_obj,"awr_m_"..wpn_sect,pos,lvID,gvID,GetAngle(_obj),wpn_fn,wpn_condition)
  261. awr_sf.dout(nil, caller, "WPN quiality is %s. Delay %s, new mesh name [awr_m_], angle %s, wpn name [%s], wpn condition %s. Calling create_call()", string.gsub(wpn_sect, 'wpn.*%_(.*)', '%1'), delay, wpn_sect, GetAngle(_obj), wpn_fn, wpn_condition)
  262. end
  263.  
  264. db.actor:drop_item(wpn)
  265. local se_obj = alife():object(wpn:id())
  266. if (se_obj) then
  267. alife():release(se_obj)
  268. end
  269. end
  270. end
  271. end
  272. if HasScope(wpn_sect) then
  273. SetHudMsg(game.translate_string("st_unload"),3)
  274. return
  275. elseif not (InWpnLst(wpn_sect)) then
  276. SetHudMsg(game.translate_string("st_not_in_list"),3)
  277. return
  278. end
  279. else
  280. SetHudMsg(game.translate_string("st_no_weap"),3)
  281. awr_sf.dout(nil, caller, "WPN is not in hands -> return")
  282. return
  283. end
  284. elseif access(_obj) and string.match(_obj:section(),"awr_m_wpn_") and _obj:position():distance_to(db.actor:position()) < 1.5 then
  285. if (wpn) then
  286. awr_sf.dout(nil, caller, "WPN variable exist")
  287. if not db.actor:active_item() then
  288. awr_sf.dout(nil, caller, "WPN is not in hands, call UI")
  289. local hud = get_hud()
  290. ui = ui_awr_menu and ui_awr_menu.awr_main_ui(hud,wpn,wpn_sect,wpn_condition,ch_obj)
  291. if (ui) then
  292. ui:ShowDialog(true)
  293. ui:FillList()
  294. end
  295. else
  296. SetHudMsg(game.translate_string("st_handsfree"),3)
  297. awr_sf.dout(nil, caller, "WPN in hands -> return")
  298. return
  299. end
  300. else
  301. actor_effects.use_item("awr_repair_dummy")
  302.  
  303. CreateTimeEvent("create_mesh","delay",delay,create_call,ch_obj,"awr_tiski",pos,lvID,gvID,GetAngle(_obj))
  304. awr_sf.dout(nil, caller, "Delay %s, new mesh name [awr_tiski], angle %s. Calling create_call()", delay, GetAngle(_obj))
  305.  
  306. local m_name = _obj:name()
  307. if m_name then
  308. if wpn_data then
  309. local new_cond = wpn_data[m_name]['condition']
  310. local time = alun_utils.table2CTime(wpn_data[m_name]['time']) or 0
  311. if game.get_game_time():diffSec(time) > settings_list.steal_delay then
  312. new_cond = new_cond - math.random(0,25)/100
  313. awr_sf.dout(nil, caller, "Difference time %s > %s -> some parts was stolen for WPN %s, old condition %s, new condition %s", game.get_game_time():diffSec(time), settings_list.steal_delay, wpn_data[m_name]['wpn_name'], wpn_data[m_name]['condition'], new_cond)
  314. SetHudMsg(game.translate_string("st_stolen_"..math.random(1,3)),3)
  315. else
  316. awr_sf.dout(nil, caller, "Difference time %s < %s -> parts was not stolen", game.get_game_time():diffSec(time), settings_list.steal_delay)
  317. end
  318. end
  319. db.actor:disable_info_portion(string.format("awr_%s_on_table", angles_t[m_name][1]))
  320. if not (db.actor:has_info(string.format("awr_%s_on_table", angles_t[p_name][1]))) then
  321. awr_sf.dout(caller, current_func, "Remove infoportion awr_%s_on_table", angles_t[p_name][1])
  322. end
  323. end
  324.  
  325. local function wpn_alife(id, obj)
  326. obj:set_condition(new_cond)
  327. obj:unload_magazine()
  328. end
  329.  
  330. local sobj = alife():create(string.gsub(_obj:section(), '^(.*)(%_)(wpn)(.*)$', '%3%4'), db.actor:position(),0,0,0)
  331.  
  332. if sobj then
  333. level.client_spawn_manager():add(sobj.id, 0, wpn_alife)
  334. end
  335. end
  336. end
  337. elseif mesh_test_mode then --// Режим тестирования мешей
  338. local ch_obj = alife():object(_obj:id())
  339. local pos, lvID, gvID = _obj:position(), _obj:level_vertex_id(), _obj:game_vertex_id()
  340.  
  341. if string.match(_obj:name(), "awr_tiski") or string.match(_obj:name(), "awr_m_") then
  342. if (ch_obj) then
  343. alife():release(ch_obj)
  344. end
  345.  
  346. local s_obj = alife():create(test_list[test_wep], pos, lvID, gvID)
  347.  
  348. if s_obj then
  349. s_obj.repack = { ["direction"] = vector():set(0,tonumber(GetAngle(_obj)),0) }
  350. end
  351.  
  352. test_wep = test_wep + 1
  353. end
  354. end
  355. end
  356.  
  357. --// Функция подсветки деталей при наведении на оружие и оружия при наведении на детали
  358. function on_item_focus(item)
  359. local t = {}
  360. local sec = nil
  361. local c_wpn = {}
  362. local det_arg = {}
  363. local wpn_parts_gen_t = {}
  364.  
  365. if IsWeapon(item) then
  366. for _, k in ipairs(weapons_list) do
  367. if string.match(item:section(), k) then
  368. c_wpn = alun_utils.parse_list(ini,"awr_weapon_list", k)
  369.  
  370. wpn_parts_gen_t = {
  371. br_t = c_wpn[1],
  372. tc_t = c_wpn[2],
  373. bc_t = c_wpn[3],
  374. b_t = c_wpn[4],
  375. gt_t = c_wpn[5]
  376. }
  377. sec = k
  378. end
  379. end
  380.  
  381. if sec then
  382. for key, val in pairs(f_details) do
  383. table.insert(t, string.format("awr_%s_%s_good", val, wpn_parts_gen_t[key]))
  384. table.insert(t, string.format("awr_%s_%s_worn", val, wpn_parts_gen_t[key]))
  385. table.insert(t, string.format("awr_%s_%s_rusty", val, wpn_parts_gen_t[key]))
  386.  
  387. for i=1,#t do
  388. ActorMenu.get_actor_menu():highlight_section_in_slot(t[i],EDDListType.iActorBag)
  389. end
  390. end
  391. end
  392. elseif IsDetail(item,"good") then
  393. for _, k in ipairs(weapons_list) do
  394. det_arg[k] = alun_utils.parse_list(ini,"awr_weapon_list", k)
  395. local type = string.gsub(string.gsub(item:section(), '^(%w+%_)(%w*)', '%2'), '(%_%d+%_%w+)$', '')
  396. local num = string.gsub(item:section(), '^(.*)(%_)(%d+)(.*)$', '%3')
  397. for n, v in ipairs(n_details) do
  398. if v == type then
  399. if det_arg[k][n] == num then
  400. table.insert(t, k)
  401. for _, z in ipairs(scopes) do
  402. table.insert(t, string.format("%s_%s", k, z))
  403. end
  404. end
  405. end
  406. end
  407. end
  408. for i=1,#t do
  409. ActorMenu.get_actor_menu():highlight_section_in_slot(t[i],EDDListType.iActorBag)
  410. end
  411. else
  412. return
  413. end
  414. end
  415.  
  416. --// Функция для работы с контекстным меню инвентаря (use2_functor) (вызывается из default_weapon_params, defines.ltx)
  417. --// Если функция вернет строку - она появится в контекстном меню при нажатии ПКМ на оружие в инвентаре
  418. --// Нажатие на строку, вызовет use2_action_functor - disassembly_weapon()
  419. function disassembly_weapon_text(weapon_obj)
  420. local n = nil
  421.  
  422. if (not weapon_obj) or not (IsWeapon(weapon_obj)) then
  423. return
  424. end
  425.  
  426. --// Обратная функция InWpnList(), для поиска секции из списка в текущей секции оружия (например для оружия с прицелом, которое имеет секцию вида "wpn_..._..._1p29")
  427. for _, k in ipairs(weapons_list) do
  428. if string.match(weapon_obj:section(), k) then
  429. n = 1
  430. end
  431. end
  432.  
  433. if not (n) then
  434. return
  435. end
  436.  
  437. return game.translate_string("st_awr_disassembly")
  438. end
  439. --// Функтор контекстного вызова разборки оружия
  440. function disassembly_weapon(weapon_obj)
  441. local caller = debug.getinfo(1, "n").name
  442. local current_func = nil
  443.  
  444. local details_am
  445. local get_detail
  446. local num
  447. local wpn_details = {}
  448. local result_details = {}
  449. local result_details_names = ""
  450. local get_ammo = {}
  451. local with_scope = nil
  452. local a_name
  453.  
  454. local wpn_s = weapon_obj:section()
  455. local wpn_name = game.translate_string(rx_utils.read_from_ini2(nil,wpn_s,"inv_name","string","error"))
  456.  
  457. awr_sf.dout(caller, current_func, "Trying to disassemble %s", wpn_s)
  458.  
  459. if (axr_main.config:r_value("mm_options","enable_extra_animations",1,false) == false) then
  460. delay = 0
  461. else
  462. delay = 100
  463. end
  464.  
  465. if not (db.actor:object("leatherman_tool")) then
  466. awr_sf.SendAwrMsg('fail', 'weapon', "st_dis_text_3", " ")
  467. awr_sf.dout(caller, current_func, "Actor dont have leathernam_tool -> return", wpn_s)
  468. return
  469. end
  470.  
  471. local details_q = { 'good', 'worn', 'rusty' }
  472. local on_drop_details = {
  473. 'barrel',
  474. 'trigger_components',
  475. 'bolt_carrier',
  476. 'bolt',
  477. 'gas_tube'
  478. }
  479.  
  480.  
  481.  
  482. if IsWeapon(weapon_obj) then
  483. for key, val in pairs(scopes) do
  484. if string.match(wpn_s, key) then
  485. with_scope = key
  486. end
  487. end
  488.  
  489. --// Проверка наличия аддонов
  490. if with_scope then
  491. table.insert(result_details, with_scope)
  492. wpn_s = string.gsub(wpn_s, "_"..with_scope, "")
  493. end
  494. if (rx_utils.addon_attached(weapon_obj,"sc")) then
  495. local scope_section = rx_utils.read_from_ini2(nil,wpn_s,"scopes_sect","string",nil)
  496. table.insert(result_details, rx_utils.read_from_ini2(nil,scope_section,"scope_name","string",nil))
  497. end
  498. if (rx_utils.addon_attached(weapon_obj,"sl") and not (string.match(wpn_s, "wpn_val")) and not (string.match(wpn_s, "wpn_vintorez")) and not (string.match(wpn_s, "wpn_vsk94"))) then
  499. table.insert(result_details, rx_utils.read_from_ini2(nil,wpn_s,"silencer_name","string",nil))
  500. end
  501. if (rx_utils.addon_attached(weapon_obj,"gl")) and not (string.match(wpn_s, "wpn_groza")) then
  502. table.insert(result_details, rx_utils.read_from_ini2(nil,wpn_s,"grenade_launcher_name","string",nil))
  503. end
  504.  
  505. --// Проверка наличия патронов в рожке
  506. local data = stpk_utils.get_weapon_data(alife():object(weapon_obj:id()))
  507. if data.ammo_elapsed > 0 then
  508. local ammos = alun_utils.parse_list(system_ini(), wpn_s, "ammo_class")
  509. get_ammo = { data.ammo_elapsed, ammos[data.ammo_type+1] }
  510. end
  511.  
  512. local wpn_cond = weapon_obj:condition()
  513.  
  514. local _wpn_details = alun_utils.parse_list(ini,"awr_weapon_list", wpn_s)
  515.  
  516. for i, k in ipairs(_wpn_details) do
  517. wpn_details[on_drop_details[i]] = k
  518. end
  519.  
  520. if awr_sf.IsRusty(wpn_s) then
  521. details_am = 2 --// Количество деталей при разборке ржавого оружия
  522. elseif awr_sf.IsWorn(wpn_s) then
  523. details_am = 2 --// Количество деталей при разборке изношенного оружия
  524. else
  525. details_am = 3 --// Количество деталей при разборке нового оружия
  526. end
  527.  
  528. local i = details_am
  529.  
  530. while i > 0 do
  531. if (wpn_cond*100)+settings_list.condition >= math.random(1, 100) then
  532. num = math.random(1,#on_drop_details)
  533. get_detail = on_drop_details[num]
  534.  
  535. if awr_sf.IsRusty(wpn_s) then
  536. table.insert(result_details, string.format("awr_%s_%i_%s", get_detail, wpn_details[get_detail], details_q[math.random(2,3)])) --// Рандом для создания ржавых деталей
  537. else
  538. table.insert(result_details, string.format("awr_%s_%i_%s", get_detail, wpn_details[get_detail], details_q[math.random(1,2)])) --// Рандом для создания изношенных и новых деталей
  539. end
  540.  
  541. table.remove(on_drop_details, num)
  542. end
  543. i = i - 1
  544. end
  545.  
  546. for _, k in ipairs(result_details) do
  547. result_details_names = result_details_names.."\\n"..game.translate_string(rx_utils.read_from_ini2(nil,k,"inv_name","string","error"))
  548. end
  549.  
  550. local se_obj = alife():object(weapon_obj:id())
  551. if (se_obj) then
  552. alife():release(se_obj)
  553. end
  554.  
  555. local function disasm()
  556. if get_ammo and get_ammo[1] and get_ammo[2] then
  557. a_name = string.format(game.translate_string("st_dis_text_4"), get_ammo[1], string.gsub(game.translate_string(rx_utils.read_from_ini2(nil,get_ammo[2],"inv_name","string",0)), "^(.*%s)(%d+)", "%2"))
  558. create_ammo(get_ammo[2], db.actor:position(), db.actor:level_vertex_id(), db.actor:game_vertex_id(), db.actor:id(), get_ammo[1])
  559. end
  560.  
  561. if #result_details > 0 then
  562. if get_ammo and get_ammo[1] and get_ammo[2] then
  563. awr_sf.SendAwrMsg('success', 'weapon_ammo', "st_dis_text_7", wpn_name, a_name, result_details_names)
  564. else
  565. awr_sf.SendAwrMsg('success', 'weapon', "st_dis_text_1", wpn_name, result_details_names)
  566. end
  567. else
  568. awr_sf.SendAwrMsg('fail', 'weapon', "st_dis_text_2", wpn_name)
  569. end
  570.  
  571. for _, k in ipairs(result_details) do
  572. alife():create(k, db.actor:position(), db.actor:level_vertex_id(), db.actor:game_vertex_id(), db.actor:id())
  573. end
  574.  
  575. return true
  576. end
  577.  
  578. actor_effects.use_item("cleaning_kit_u_dummy")
  579. CreateTimeEvent("disasm","delay",delay,disasm,weapon_obj)
  580. else
  581. return
  582. end
  583. end
  584.  
  585. --// Функтор контекстного вызова восстановления детали (текст)
  586. function r_detail_text(itm)
  587. if not (itm) and not (IsDetail(itm,'worn')) and not (IsDetail(itm,'rusty')) then
  588. return
  589. end
  590. return game.translate_string("st_awr_r_detail")
  591. end
  592.  
  593. --// Функтор контекстного вызова восстановления детали
  594. function r_detail(itm)
  595. if (ui) and ui:IsShown() then
  596. ui:HideDialog()
  597. end
  598.  
  599. local hud = get_hud()
  600. ui = ui_awr_mini and ui_awr_mini.awr_mini_ui(hud,itm)
  601. if (ui) then
  602. ui:ShowDialog(true)
  603. end
  604. end
  605.  
  606. --// Функция проверки, является ли предмет деталью. Список генерируется динамически. При изменении количества деталей, изменить значения в файле awr_settings на соответствующее.
  607. function IsDetail(item,type)
  608. local caller = debug.getinfo(1, "n").name
  609. local current_func = debug.getinfo(2, "n").name
  610.  
  611. local x = 1
  612. local all_details_f = {}
  613. local all_details = {
  614. bolt = settings_list.bolt,
  615. barrel = settings_list.barrel,
  616. gas_tube = settings_list.gas_tube,
  617. bolt_carrier = settings_list.bolt_carrier,
  618. trigger_components = settings_list.trigger
  619. }
  620.  
  621.  
  622. for key, val in pairs(all_details) do
  623. while x < val+1 do
  624. table.insert(all_details_f, "awr_"..key.."_"..x.."_"..type)
  625. x = x + 1
  626. end
  627. x = 1
  628. end
  629.  
  630. if item then
  631. for _, k in ipairs(all_details_f) do
  632. if k == item:section() then
  633. awr_sf.dout(caller, current_func, "%s is detail", item:section())
  634. return true
  635. end
  636. end
  637. else
  638. awr_sf.dout(caller, current_func, "Detail object is nil -> return")
  639. return
  640. end
  641. end
  642.  
  643. --// Функция проверки наличия itm в списке подходящего оружия из файла awr_settings
  644. function InWpnLst(itm)
  645. local caller = debug.getinfo(1, "n").name
  646. local current_func = debug.getinfo(2, "n").name
  647.  
  648. for _, k in ipairs(weapons_list) do
  649. if k == itm then
  650. awr_sf.dout(caller, current_func, "WPN %s in AWR weapons compatible list", itm)
  651. return true
  652. end
  653. end
  654. awr_sf.dout(caller, current_func, "WPN %s is NOT in AWR weapons compatible list", itm)
  655. end
  656.  
  657. function HasScope(wpn_sect)
  658. local caller = debug.getinfo(1, "n").name
  659. local current_func = debug.getinfo(2, "n").name
  660.  
  661. for _, k in ipairs(scopes) do
  662. if string.match(wpn_sect, string.format('wpn.*%_%s$', k)) then
  663. awr_sf.dout(caller, current_func, "WPN %s has attached %s scope -> return", wpn_sect, k)
  664. return true
  665. end
  666. end
  667. end
  668.  
  669. --// Функция получения значения угла для установки меша, исходя из секции механика в радиусе n-метров
  670. function GetAngle(obj)
  671. local caller = debug.getinfo(1, "n").name
  672. local current_func = debug.getinfo(2, "n").name
  673.  
  674. awr_sf.dout(caller, current_func, "Called for %s", obj:name())
  675. if not (obj) or not (string.match(obj:name(), "awr")) then --// У объектов, заспавненных через all.spawn, секция physic object
  676. return
  677. end
  678.  
  679. local name = awr_sf.get_p_name(obj:name())
  680. if angles_t[name] then
  681. awr_sf.dout(caller, current_func, "Angle for %s = %s", name, angles_t[name][2] or 0)
  682. awr_sf.s_v(name, angles_t[name])
  683. return angles_t[name][2] or 0
  684. end
  685. end
  686.  
  687. --// Коллбэк при смерти механика
  688. function OnDeath(npc)
  689. local caller = debug.getinfo(1, "n").name
  690. local current_func = debug.getinfo(2, "n").name
  691.  
  692. awr_sf.dout(caller, current_func, "Called for NPC, %s", npc:section())
  693. if IsStalker(npc) and not (npc:alive()) then
  694. local npc_s = npc:section()
  695. awr_sf.dout(caller, current_func, "NPC %s exist and dead", npc:section())
  696. for key, val in pairs(angles_t) do
  697. for _, v in ipairs(angles_t[key]) do
  698. if angles_t[key][1] == npc_s then
  699. angles_t[key][3] = 'dead'
  700. if db.actor:has_info("awr_go_away") then
  701. db.actor:disable_info_portion("awr_go_info")
  702. end
  703.  
  704. level.map_add_object_spot_ser(get_story_object(angles_t[key][1]):id(), "ui_pda2_mechanic_location", "st_mech_tiski")
  705. db.actor:give_info_portion(string.format("awr_%s_dead", npc_s))
  706. awr_sf.LampOn(npc_s)
  707. awr_sf.s_v(key, angles_t[key])
  708.  
  709. end
  710. end
  711. end
  712. end
  713. end
  714.  
  715. --// Функция закрытия UI AWR по окончании времени (при условии, что UI вызван, и actor находится в пределах 2 метров от меша)
  716. function CloseDl()
  717. local caller = debug.getinfo(1, "n").name
  718. local current_func = debug.getinfo(2, "n").name
  719.  
  720. for i=1, 65535 do
  721. local s_obj = alife():object(i)
  722. if s_obj then
  723. local c_obj = level.object_by_id(s_obj.id)
  724. if c_obj then
  725. if string.match(s_obj:name(), "awr_m_") and c_obj:position():distance_to(db.actor:position()) <= 2 then
  726. awr_sf.dout(caller, current_func, "Called for %s, distance = %s <= 2", s_obj:name(), c_obj:position():distance_to(db.actor:position()))
  727. if (ui) and ui:IsShown() then
  728. awr_sf.dout(caller, current_func, "UI exist and show")
  729. ui:Exit()
  730. end
  731. end
  732. end
  733. end
  734. end
  735. end
  736.  
  737. function npc_on_death_callback(victim, who)
  738. if not (victim) or not (who) then
  739. return
  740. end
  741. local name = string.gsub(victim:name(), '%d+', '')
  742.  
  743. if mech_list_key[name] then
  744. local caller = debug.getinfo(1, "n").name
  745. local current_func = debug.getinfo(2, "n").name
  746.  
  747. awr_shared_functions.dout(caller, current_func, "NPC %s was killed by %s.", victim:name(), who:name())
  748.  
  749. OnDeath(victim)
  750.  
  751. local killer_name = who:character_name()
  752.  
  753. if who:id() == db.actor:id() then
  754. local alife = alife()
  755. local se_actor = alife:actor()
  756. killer_name = se_actor:character_name()
  757. end
  758. awr_shared_functions.SendAwrMsg('success', 'npc', "st_awr_dead_mechanic", victim:character_name(), killer_name or game.translate_string("st_by_unknown"))
  759. else
  760. return
  761. end
  762. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement