Advertisement
Guest User

sim_squad_scripted.script

a guest
Jun 12th, 2010
478
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 38.88 KB | None | 0 0
  1. --'******************************************************
  2. --'*    Áîåâîé îòðÿä ãðóïïèðîâêè. (Ñêðèïòîâàÿ âåðñèÿ)
  3. --'*    Íàñëåäîâàí îò îáû÷íîãî áîåâîãî îòðÿäà.
  4. --'*    Îòëè÷èÿ:
  5. --'*        - Äåòåðìèíèðîâàííûå ñîñòàâ îòðÿäà
  6. --'*        - Âîçìîæíîñòü æåñòêî óêàçàòü àêòèâíîå äåéñòâèå
  7. --'******************************************************
  8. local squad_behaviour_ini   = ini_file("misc\\squad_behaviours.ltx")
  9. local locations_ini         = ini_file("misc\\smart_terrain_masks.ltx")
  10. --function printf()
  11. --end
  12.  
  13. class "sim_squad_scripted" (cse_alife_online_offline_group)
  14.  
  15. --***********************************************************************************************
  16. --*                                     INITIALIZATION                                          *
  17. --***********************************************************************************************
  18.  
  19. function sim_squad_scripted:__init(section) super (section)
  20.     --' ñìàðò, â êîòîðîì ñåé÷àñ íàõîäèòñÿ îòðÿä.
  21.     self.smart_id           = nil
  22.     self.board              = sim_board.get_sim_board()
  23.     self.current_spot_id    = nil --' ID îáúåêòà íà êîòîðûé ñåé÷àñ óñòàíîâëåí ìàïñïîò.
  24.  
  25.     --' Òåêóùåå äåéñòâèå
  26.     self.current_action     = nil
  27.  
  28.     self.current_target_id  = nil
  29.  
  30.     self.assigned_target_id = nil
  31.  
  32.     --' Ñàóíäìåíåäæåð îòðÿäà
  33.     self.sound_manager      = sound_manager.get_sound_manager("squad_"..self:section_name() )
  34.  
  35.     self.settings_id        = self:section_name()
  36.  
  37.     self:init_squad()
  38.  
  39.     self:set_squad_behaviour()
  40. end
  41. --' Èíèöèàëèçàöèÿ
  42. function sim_squad_scripted:init_squad()
  43.     self.player_id          = utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "faction", self, true, "")
  44.     self.action_condlist    = xr_logic.parse_condlist(self, "assign_action", "target_smart", utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "target_smart", self, false, "", ""))
  45.     self.death_condlist     = xr_logic.parse_condlist(self, "death_condlist", "on_death", utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "on_death", self, false, "", ""))
  46.     self.invulnerability    = xr_logic.parse_condlist(self, "invulnerability", "invulnerability", utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "invulnerability", self, false, "", ""))
  47.     self.relationship       = self.relationship or utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "relationship", self, false, "", nil)
  48.     self.sympathy           = utils.cfg_get_number(sim_board.squad_ltx, self.settings_id, "sympathy", self, false, nil)
  49.     self.show_spot          = xr_logic.parse_condlist(self, "show_spot", "show_spot", utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "show_spot", self, false, "", "false"))
  50.  
  51.     self.always_walk        = utils.cfg_get_bool(sim_board.squad_ltx, self.settings_id, "always_walk", self, false)
  52.     self.always_arrived     = utils.cfg_get_bool(sim_board.squad_ltx, self.settings_id, "always_arrived", self, false)
  53.     self:set_location_types_section("stalker_terrain")
  54.     self:set_squad_sympathy()
  55. end
  56.  
  57. -- Èíèöèàëèçàöèÿ îòðÿäà íà çàãðóçêå
  58. function sim_squad_scripted:init_squad_on_load()
  59.     -- Ïðîïèñûâàåì ñêâàä â íóæíûå ñìàðòû
  60.     printf("Init squad %s on load", self.id)
  61.     self:set_squad_sympathy()
  62.     self.board:assign_squad_to_smart(self, self.smart_id)
  63.  
  64.     if self.smart_id ~= nil then
  65.         self.board:enter_smart(self, self.smart_id, true)
  66.     end
  67.     self.need_to_reset_location_masks = true
  68. end
  69.  
  70. -- Âû÷èòûâàåì íàñòðîéêè ïîâåäåíèÿ ñêâàäà.
  71. function sim_squad_scripted:set_squad_behaviour()
  72.     self.behaviour      = {}
  73.     local behaviour_section = utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "behaviour", self, false, "", self.player_id)
  74.     if not squad_behaviour_ini:section_exist(behaviour_section) then
  75.         abort("There is no section ["..behaviour_section.."] in 'misc\\squad_behaviours.ltx'")
  76.     end
  77.     local n = squad_behaviour_ini:line_count(behaviour_section)
  78.     for j=0,n-1 do
  79.         local result, prop_name, prop_condlist = squad_behaviour_ini:r_line(behaviour_section,j,"","")
  80.         self.behaviour[prop_name] = prop_condlist
  81.     end
  82. end
  83.  
  84. --***********************************************************************************************
  85. --*                                     SCRIPT_TARGET_SELECTION                                 *
  86. --***********************************************************************************************
  87.  
  88. --' Âîçâðàùàåò ñêðèïòîâóþ öåëü.
  89. function sim_squad_scripted:get_script_target()
  90.     local new_target = xr_logic.pick_section_from_condlist(db.actor, self, self.action_condlist)
  91.  
  92.     if new_target == nil then
  93. --      printf("[%s] get_script_target nil_condlist", self.id)
  94.         return nil
  95.     end
  96.  
  97.     if new_target ~= self.last_target then
  98.         self.last_target = new_target
  99.         --' Ïàðñèì íîâûå çàäà÷è äëÿ îòðÿäà
  100.         self.parsed_targets = utils.parse_names(new_target)
  101.  
  102.         if self.need_free_update ~= true then
  103.             self.next_target = 1
  104.         else
  105.             self.need_free_update = false
  106.         end
  107.     end
  108.     if self.parsed_targets[self.next_target] == nil then
  109.         self.next_target = 1
  110.     end
  111.  
  112.  
  113.     local nt = self:pick_next_target()
  114.     if nt == "nil" then
  115.         return nil
  116.     elseif nt == "loop" then
  117.         self.next_target = 1
  118.         nt = self:pick_next_target()
  119.     end
  120.     local point = self.board.smarts_by_names[nt]
  121.     if point == nil then
  122.         abort("Incorrect next point [%s] for squad [%s]", tostring(nt),  tostring(self.id))
  123.     end
  124.     return point.id
  125. end
  126.  
  127.  
  128. --' Âûáîð ñëåäóþùåé öåëè
  129. function sim_squad_scripted:pick_next_target()
  130.     --printf("Picking next target for [%s] = %s by %s", self:section_name(), tostring(self.parsed_targets[self.next_target]), self.next_target)
  131.     return self.parsed_targets[self.next_target]
  132. end
  133.  
  134.  
  135. --' Ïðîâåðêà ïðèøåë ëè îòðÿä â î÷åðåäíîé ïîèíò
  136. function sim_squad_scripted:check_squad_come_to_point()
  137.     --printf("[%s] check squad point", self.id)
  138.     if self.parsed_targets == nil then
  139.         return true
  140.     end
  141.     --' Åñëè ìû óæå äîøëè äî òî÷êè.
  142.     local next_target = self.next_target or 0
  143.     if self.assigned_target_id ~= nil and self.smart_id == self.assigned_target_id then
  144.         if self.parsed_targets[next_target+1] ~= nil then
  145.             self.next_target = next_target+1
  146.             return true
  147.         end
  148.     end
  149.     return false
  150. end
  151.  
  152. --' Ïðîâåðêà ïðèøåë ëè îòðÿä â î÷åðåäíîé ïîèíò
  153. function sim_squad_scripted:update_current_action()
  154.     local is_finished = self.current_action:update(false)
  155.     if not is_finished then
  156.         return false
  157.     end
  158.     return true
  159. end
  160.  
  161. function sim_squad_scripted:update()
  162.     cse_alife_online_offline_group.update (self)
  163.     self:refresh()
  164.  
  165.     -- Àïäåéò äîñòóïíîñòè äëÿ ñèìóëÿöèè.
  166.     simulation_objects.get_sim_obj_registry():update_avaliability(self)
  167.  
  168.     self:check_invulnerability()
  169.  
  170.     local script_target = self:get_script_target()
  171.  
  172.     --printf("[%s] SCRIPTED UPDATE. Target[%s]", self.id, tostring(script_target))
  173.     if script_target == nil then
  174.         self:generic_update()
  175.         if self.need_to_reset_location_masks then
  176.             self:set_location_types()
  177.             self.need_to_reset_location_masks = false
  178.         end
  179.         return
  180.     end
  181.  
  182.     self.sound_manager:update()
  183.  
  184.     local need_to_find_new_action = false
  185.     if self.assigned_target_id ~= nil and self.assigned_target_id == script_target then
  186.         if self.current_action ~= nil then
  187.             if self.current_action.name == "stay_point" then
  188.                 --' Åñëè ýêøí stay_point. Ïðîâåðÿåì ïðèøëè ëè äî ýêøíà.
  189.                 if self:check_squad_come_to_point() then
  190.                     --' Ïðèøëè â òî÷êó, ïåðåâûáðàëè öåëü
  191.                     need_to_find_new_action = true
  192.                     --printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
  193.                 else
  194.                     --' Íå ïðèøëè â òî÷êó, àïäåéòèìñÿ äàëüøå
  195.                     need_to_find_new_action = self:update_current_action()
  196.                     --printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
  197.                 end
  198.             else
  199.                 --' Åñëè ýêøí attack_point. Ïðîâåðÿåì ïðèøëè ëè ïîñëå ýêøíà.
  200.                 if self:update_current_action() then
  201.                     self:check_squad_come_to_point()
  202.                     need_to_find_new_action = true
  203.                     --printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
  204.                 end
  205.             end
  206.         else
  207.             --' Ïðîâåðÿåì ïðèøëè ëè
  208.             self:check_squad_come_to_point()
  209.             need_to_find_new_action = true
  210.             --printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
  211.         end
  212.     else
  213.         if self.current_action == nil then
  214.             need_to_find_new_action = true
  215.             --printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
  216.         else
  217.             if self.current_action.major == true then
  218.                 if self:update_current_action() then
  219.                     self:check_squad_come_to_point()
  220.                     need_to_find_new_action = true
  221.                     --printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
  222.                 end
  223.             else
  224.                 need_to_find_new_action = true
  225.                 --printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
  226.             end
  227.         end
  228.     end
  229.  
  230.     if need_to_find_new_action == true then
  231.         self.assigned_target_id = script_target
  232.  
  233.         if self.current_action ~= nil then
  234.             self.current_action:finalize()
  235.             self.current_action = nil
  236.         end
  237.         --' Åñëè ó íàñ íåò òåêóùåé öåëè - ïðîñèì âûäàòü íàì çàäàíèå.
  238.         self:get_next_action(false)
  239.     end
  240.     if self.need_to_reset_location_masks then
  241.         self:set_location_types()
  242.         self.need_to_reset_location_masks = false
  243.     end
  244. end
  245.  
  246.  
  247.  
  248. --***********************************************************************************************
  249. --*                                     SIMULATION_TARGET_SELECTION                             *
  250. --***********************************************************************************************
  251.  
  252. function sim_squad_scripted:clear_assigned_target()
  253.     self.assigned_target_id = nil
  254. end
  255.  
  256. function sim_squad_scripted:assigned_target_avaliable()
  257.     local target_obj = self.assigned_target_id and alife():object(self.assigned_target_id)
  258.     if target_obj == nil then
  259.         return false
  260.     end
  261.     --  äàííîì ñëó÷àå íóæíî ïðîâåðÿòü ïîïüþëåéøí ìèíóñ îäèí, ò.ê. ÿ óæå ñîñòîþ â ñìàðòå.
  262.     return target_obj:target_precondition(self, true)
  263. end
  264.  
  265. local function can_help_actor(squad)
  266.     if empty(xr_combat_ignore.fighting_with_actor_npcs) then
  267.         return false
  268.     end
  269.     if game_graph():vertex(squad.m_game_vertex_id):level_id() ~= game_graph():vertex(alife():actor().m_game_vertex_id):level_id() then
  270.         return false
  271.     end
  272.     if has_alife_info("sim_duty_help_harder") and squad:get_squad_community() == "duty" then
  273.         return true
  274.     elseif has_alife_info("sim_freedom_help_harder") and squad:get_squad_community() == "freedom" then
  275.         return true
  276.     elseif has_alife_info("sim_stalker_help_harder") and squad:get_squad_community() == "stalker" then
  277.         return true
  278.     end
  279.  
  280.     local c_id = squad and squad:commander_id()
  281.     local commander = c_id and level.object_by_id(c_id)
  282.     if ( commander and commander:has_info("npcx_axr_info_is_actor_companion") ) then
  283.         return true
  284.     end
  285.  
  286.     return false
  287. end
  288.  
  289. local function get_help_target_id(squad)
  290.     if not can_help_actor(squad) then
  291.         return nil
  292.     end
  293.     for k,v in pairs (xr_combat_ignore.fighting_with_actor_npcs) do
  294.         local enemy_squad_id = alife():object(k).group_id
  295.         if enemy_squad_id ~= nil then
  296.             local target_squad = alife():object(enemy_squad_id)
  297.             if target_squad and squad.position:distance_to_sqr(target_squad.position) < 150^2 and game_relations.is_factions_enemies(squad:get_squad_community(), target_squad:get_squad_community()) then
  298.                 return enemy_squad_id
  299.             else
  300.                 if ( target_squad ) then
  301.                     local c_id = squad and squad:commander_id()
  302.                     local commander = c_id and level.object_by_id(c_id)
  303.                     if ( commander and commander:has_info("npcx_axr_info_is_actor_companion") ) then
  304.                         return enemy_squad_id
  305.                     end
  306.                 end
  307.             end
  308.         end
  309.     end
  310.     return nil
  311. end
  312.  
  313.  
  314. --' Àïäåéò îòðÿäà äëÿ âûáîðà ñèìóëÿöèîííûõ öåëåé.
  315. function sim_squad_scripted:generic_update()
  316.     --printf("Squad[%s] UPDATE", self.id)
  317.     --' Åñëè ó íàñ åñòü íåçàâåðøåííîå äåéñòâèå - æäåì ïîêà îíî çàâåðøèòñÿ.
  318.     self.sound_manager:update()
  319.     self:refresh()
  320.  
  321.     local help_target_id = get_help_target_id(self)
  322.  
  323.     if help_target_id then
  324.         self.assigned_target_id = help_target_id
  325.         self.current_action = nil
  326.         self:get_next_action(false)
  327.         return
  328.     end
  329.     if self.assigned_target_id and alife():object(self.assigned_target_id) and alife():object(self.assigned_target_id):clsid() ~= clsid.online_offline_group_s then
  330.         local squad_target = self.board:get_squad_target(self)
  331.         if squad_target:clsid() == clsid.online_offline_group_s then
  332.             self.assigned_target_id = squad_target.id
  333.             self.current_action = nil
  334.             self:get_next_action(true)
  335.             return
  336.         end
  337.     end
  338.  
  339.     if self.current_action ~= nil and self:assigned_target_avaliable() then
  340.         --printf("[%s] CURRENT ACTION [%s]", self.id, self.current_action.name)
  341.         local is_finished = self.current_action:update(true)
  342.  
  343.         if is_finished then
  344.             self.current_action:finalize()
  345.             if self.current_action.name == "stay_point" or self.assigned_target_id == nil then
  346.                 self.assigned_target_id = self.board:get_squad_target(self).id
  347.             end
  348.             self.current_action = nil
  349.         else
  350.             return
  351.         end
  352.     else
  353.         self.current_action = nil
  354.         self.current_target_id = nil
  355.         self.assigned_target_id = self.board:get_squad_target(self).id
  356.     end
  357.     self:get_next_action(true)
  358. end
  359. --' Ïîëó÷åíèå ñëåäóþùåãî ýêøíà íà âûïîëíåíèå
  360. function sim_squad_scripted:get_next_action(under_simulation)
  361.     local squad_target = alife():object(self.assigned_target_id)
  362.     --printf("assigned_target = [%s]", tostring(self.assigned_target_id))
  363.     if self.current_target_id == nil then
  364.         if squad_target == nil or squad_target:am_i_reached(self) then
  365.             if squad_target ~= nil then
  366.                 squad_target:on_reach_target(self)
  367.                 squad_target:on_after_reach(self)
  368.             end
  369.             self.current_action = sim_squad_actions.stay_on_target(self)
  370.             self.current_target_id = self.assigned_target_id
  371.             self.current_action:make(under_simulation)
  372.             return
  373.         end
  374.     end
  375.  
  376.     if (self.assigned_target_id == self.current_target_id) or self.assigned_target_id == nil then
  377.         self.current_action = sim_squad_actions.stay_on_target(self)
  378.         self.current_target_id = self.assigned_target_id
  379.         self.current_action:make(under_simulation)
  380.     else
  381.         self.current_action = sim_squad_actions.reach_target(self)
  382.         self.current_action:make(under_simulation)
  383.     end
  384. end
  385.  
  386. --***********************************************************************************************
  387. --*                                     MEMBERS_CONTROL                                         *
  388. --***********************************************************************************************
  389. --' Óäàëåíèå ïåðñîíàæåé îòðÿäà
  390. function sim_squad_scripted:remove_squad()
  391.     local squad_npcs = {}
  392.     for k in self:squad_members() do
  393.         squad_npcs[k.id] = true
  394.     end
  395. --
  396.     for j,v in pairs(squad_npcs) do
  397.         local obj = alife():object(j)
  398.         if obj ~= nil then
  399.             self:unregister_member(j)
  400.             alife():release(obj, true)
  401.         end
  402.     end
  403.     self:hide()
  404. --  alife():release(self, true)
  405. end
  406. --' Óäàëåíèå êîíêðåòíîãî ïåðñîíàæà îòðÿäà
  407. function sim_squad_scripted:remove_npc(npc_id)
  408.     local npc = alife():object(npc_id)
  409.     self:on_npc_death(npc)
  410.     --printf("releasing object ["..npc:name().."]")
  411.     alife():release(npc, true)
  412. end
  413. --' Óáèéñòâî ÍÏÑ
  414. function sim_squad_scripted:on_npc_death(npc)
  415.     printf("Squad %s. Killed member %s", tostring(self.id), npc.id)
  416.  
  417.     self.sound_manager:unregister_npc(npc.id)
  418.     self:unregister_member(npc.id)
  419.  
  420.     if self:npc_count() == 0 then
  421.         printf("REMOVING DEAD SQUAD %s", tostring(self.id))
  422.         if self.current_action ~= nil then
  423.             self.current_action:finalize()
  424.             self.current_action = nil
  425.         end
  426.  
  427.         if self.death_condlist ~= nil then
  428.             xr_logic.pick_section_from_condlist(db.actor, self, self.death_condlist)
  429.         end
  430.         self.board:remove_squad(self)
  431.         return
  432.     end
  433.     self:refresh()
  434. end
  435. function sim_squad_scripted:assign_squad_member_to_smart(member_id, smart, old_smart_id)
  436.     local obj = alife():object(member_id)
  437.     if obj ~= nil then
  438.         --printf("    npc [%s] smart [%s]", obj:name(), tostring(obj.m_smart_terrain_id))
  439.         if obj.m_smart_terrain_id == self.smart_id then
  440.             return
  441.         end
  442.  
  443.         if obj.m_smart_terrain_id ~= 65535 and old_smart_id ~= nil and (obj.m_smart_terrain_id == old_smart_id) and self.board.smarts[old_smart_id] ~= nil then
  444.             self.board.smarts[old_smart_id].smrt:unregister_npc(obj)
  445.         end
  446.  
  447.         if smart ~= nil then
  448.             smart:register_npc(obj)
  449.         end
  450.     end
  451. end
  452. --' Íàçíà÷åíèå ñìàðòà
  453. function sim_squad_scripted:assign_smart(smart)
  454.     local old_smart = self.smart_id
  455.     self.smart_id = smart and smart.id
  456.     --printf("  squad %s assign smart. old[%s] new[%s]", self.id, tostring(old_smart), tostring(self.smart_id))
  457.     --callstack()
  458.     for k in self:squad_members() do
  459.         self:assign_squad_member_to_smart(k.id, smart, old_smart)
  460.     end
  461. end
  462.  
  463. function sim_squad_scripted:check_invulnerability()
  464.     if self.squad_online ~= true then
  465.         return
  466.     end
  467.     local invulnerability = xr_logic.pick_section_from_condlist(db.actor, self, self.invulnerability) == "true"
  468.  
  469.     for k in self:squad_members() do
  470.         local npc_st = db.storage[k.id]
  471.         if npc_st ~= nil then
  472.             local npc = npc_st.object
  473.             if npc:invulnerable() ~= invulnerabilty and utils.cfg_get_string(npc_st.ini, npc_st.active_section, "invulnerable", npc, false, "", nil) == nil  then
  474. --              printf("RESET INVULNERABILITY. npc[%s] = [%s]", npc:name(), tostring(invulnerability))
  475.                 npc:invulnerable(invulnerability)
  476.             end
  477.         end
  478.     end
  479. end
  480.  
  481. function sim_squad_scripted:set_location_types_section (section)
  482. --  printf("set_location_types_section[%s] for [%s]", tostring(section), tostring(self:name()))
  483.     if locations_ini:section_exist(section) then
  484.         local result, id, value = locations_ini:r_line(section,0,"","")
  485.         self:add_location_type(id)
  486.     end
  487. end
  488. function sim_squad_scripted:set_location_types(new_smart_name)
  489.     local default_location = "stalker_terrain"
  490.     printf("set_location_types for squad [%s]", self:name())
  491.     self:clear_location_types()
  492.     --[[for k,v in pairs(simulation_objects.get_sim_obj_registry().objects) do
  493.         if alife():object(k):clsid() == clsid.smart_terrain then
  494.             self:set_location_types_section(alife():object(k):name())
  495.         end
  496.     end]]--
  497.  
  498.     if alife():object(self.assigned_target_id):clsid() == clsid.smart_terrain then
  499.         self:set_location_types_section(default_location)
  500.         local old_smart_name = self.smart_id and alife():object(self.smart_id) and alife():object(self.smart_id):name()
  501.         --printf("old_smart_name = [%s]!", tostring(old_smart_name))
  502.         if old_smart_name then
  503.             self:set_location_types_section(old_smart_name)
  504.         end
  505.         --printf("new_smart_name = [%s]!", tostring(new_smart_name))
  506.         if new_smart_name then
  507.             self:set_location_types_section(new_smart_name)
  508.         end
  509.     else
  510.         --printf("target is squad or actor setting [squad_terrain]!")
  511.         self:set_location_types_section("squad_terrain")
  512.         for k,v in pairs(simulation_objects.get_sim_obj_registry().objects) do
  513.             if alife():object(k):clsid() == clsid.smart_terrain then
  514.                 local props_base = alife():object(k).props and alife():object(k).props["base"]
  515.                 if props_base and tonumber(props_base) == 0 then
  516.                     self:set_location_types_section(alife():object(k):name())
  517.                 end
  518.             end
  519.         end
  520.     end
  521. end
  522.  
  523. function sim_squad_scripted:add_squad_member(spawn_section, spawn_position, lv_id, gv_id, sect_number)
  524.     local spawn_sections_ltx = system_ini()
  525.     local custom_data = utils.cfg_get_string(spawn_sections_ltx, spawn_section, "custom_data", self, false, "", "default_custom_data.ltx")
  526.     if custom_data ~= "default_custom_data.ltx" then
  527.         printf("INCORRECT npc_spawn_section USED [%s]. You cannot use npc with custom_data in squads", spawn_section)
  528.     end
  529.  
  530.     local position = spawn_position
  531.  
  532.     local obj =  alife():create(spawn_section,
  533.                                 position,
  534.                                 lv_id,
  535.                                 gv_id)
  536.  
  537.     self:register_member(obj.id)
  538.     self.sound_manager:register_npc(obj.id)
  539.  
  540.     if simulation_objects.is_on_the_same_level(obj, alife():actor()) and position:distance_to_sqr(alife():actor().position) <= alife():switch_distance()^2 then
  541.         db.spawned_vertex_by_id[obj.id] = lv_id
  542.     end
  543.  
  544.     return obj.id
  545. end
  546.  
  547. --' Ñîçäàíèå ÷óâàêîâ â îòðÿä
  548. function sim_squad_scripted:create_npc(spawn_smart)
  549.     local ini = system_ini()
  550.     local spawn_sections = utils.parse_names(utils.cfg_get_string(ini, self.settings_id, "npc", self, false, "", ""))
  551.  
  552.     local spawn_point = utils.cfg_get_string(ini, self.settings_id, "spawn_point", self, false, "","self") or
  553.                         utils.cfg_get_string(spawn_smart.ini, smart_terrain.SMART_TERRAIN_SECT, "spawn_point", self, false,"","self")
  554.     spawn_point = xr_logic.parse_condlist(self, "spawn_point", "spawn_point", spawn_point)
  555.     spawn_point = xr_logic.pick_section_from_condlist(db.actor, self, spawn_point)
  556.  
  557.     --print_table(debug.getinfo(1))
  558.     printf("SPAWN SMART %s", spawn_smart:name())
  559.     --' Âûñ÷èòûâàåì áàçîâóþ ïîçèöèþ ñïàóíà
  560.     local base_spawn_position = spawn_smart.position
  561.     local base_lvi = spawn_smart.m_level_vertex_id
  562.     local base_gvi = spawn_smart.m_game_vertex_id
  563.     if spawn_point ~= nil then
  564.         if spawn_point == "self" then
  565.             base_spawn_position = spawn_smart.position
  566.             base_lvi = spawn_smart.m_level_vertex_id
  567.             base_gvi = spawn_smart.m_game_vertex_id
  568.         else
  569.             base_spawn_position = patrol(spawn_point):point(0)
  570.             base_lvi = patrol(spawn_point):level_vertex_id(0)
  571.             base_gvi = patrol(spawn_point):game_vertex_id(0)
  572.         end
  573.     elseif spawn_smart.spawn_point ~= nil then
  574.         base_spawn_position = patrol(spawn_smart.spawn_point):point(0)
  575.         base_lvi = patrol(spawn_smart.spawn_point):level_vertex_id(0)
  576.         base_gvi = patrol(spawn_smart.spawn_point):game_vertex_id(0)
  577.     end
  578.     if #spawn_sections ~= 0 then
  579.         for k,v in pairs(spawn_sections) do
  580.             self:add_squad_member(v, base_spawn_position, base_lvi, base_gvi,k)
  581.         end
  582.     end
  583.  
  584.     -- ïîäñïàóí ðýíäîìíûõ ÷óâàêîâ...
  585.     local random_spawn = utils.cfg_get_string(ini, self.settings_id, "npc_random", self, false, "",nil)
  586.     if random_spawn ~= nil then
  587.         random_spawn                =   utils.parse_names(random_spawn)
  588.         local count_min, count_max  = utils.r_2nums( ini,  self.settings_id, "npc_in_squad", 1, 2 )
  589.         if count_min > count_max then
  590.             abort("min_count can't be greater then max_count [%s]!!!!!", self.settings_id)
  591.         end
  592.         local random_count          = math.random(count_min, count_max)
  593.         for i = 1,random_count do
  594.             local random_id = math.random(1, #random_spawn)
  595.             self:add_squad_member(random_spawn[random_id], base_spawn_position, base_lvi, base_gvi,random_id)
  596.         end
  597.     elseif #spawn_sections == 0 then
  598.         abort("You are trying to spawn an empty squad [%s]!!!", self.settings_id)
  599.     end
  600.  
  601.  
  602.     self.smart_id = spawn_smart.id
  603.     self:refresh()
  604. end
  605.  
  606. function sim_squad_scripted:set_squad_sympathy(sympathy)
  607.     local symp = sympathy or self.sympathy
  608.     if(symp~=nil) then
  609.         for k in self:squad_members() do
  610.             local npc = db.storage[k.id] and db.storage[k.id].object
  611.             if(npc) then
  612.                 game_relations.set_npc_sympathy(npc, symp)
  613.             else
  614.                 if(db.goodwill.sympathy==nil) then
  615.                     db.goodwill.sympathy = {}
  616.                 end
  617.                 db.goodwill.sympathy[k.id] = symp
  618.             end
  619.         end
  620.     end
  621. end
  622. local function set_relation(npc1, npc2, new_relation)
  623.     local goodwill = 0
  624.     if(new_relation=="enemy") then
  625.         goodwill = -1000
  626.     elseif(new_relation=="friend") then
  627.         goodwill = 1000
  628.     end
  629.     if npc1 and npc2 then
  630.         npc1:force_set_goodwill(goodwill, npc2.id)
  631.     else
  632.         abort("Npc not set in goodwill function!!!")
  633.     end
  634. end
  635. function sim_squad_scripted:set_squad_relation(relation)
  636.     local rel = relation or self.relationship
  637.     if(rel~=nil) then
  638.         for k in self:squad_members() do
  639.             local npc = db.storage[k.id] and db.storage[k.id].object
  640.             if(npc) then
  641.                 game_relations.set_npcs_relation(npc, db.actor, rel)
  642.             else
  643.                 set_relation(alife():object(k.id), alife():actor(),rel)
  644.             end
  645.         end
  646.     end
  647. end
  648.  
  649.  
  650. local function reset_animation(npc)
  651.     local state_mgr = db.storage[npc:id()].state_mgr
  652.     if state_mgr == nil then
  653.         return
  654.     end
  655.     local planner = npc:motivation_action_manager()
  656.  
  657.     state_mgr.animation:set_state(nil, true)
  658.     state_mgr.animation:set_control()
  659.     state_mgr.animstate:set_state(nil, true)
  660.     state_mgr.animstate:set_control()
  661.  
  662.     state_mgr:set_state("idle", nil, nil, nil, {fast_set = true})
  663.  
  664. --  planner:update()
  665. --  planner:update()
  666. --  planner:update()
  667.  
  668.     state_mgr:update()
  669.     state_mgr:update()
  670.     state_mgr:update()
  671.     state_mgr:update()
  672.     state_mgr:update()
  673.     state_mgr:update()
  674.     state_mgr:update()
  675.  
  676.     npc:set_body_state(move.standing)
  677.     npc:set_mental_state(anim.free)
  678.  
  679. end
  680.  
  681. function sim_squad_scripted:set_squad_position(position)
  682.     if self.online == false then
  683.         self:force_change_position(position)
  684.     end
  685.  
  686.     for k in self:squad_members() do
  687.         local cl_object = level.object_by_id(k.id)
  688.         db.offline_objects[k.id].level_vertex_id = level.vertex_id(position)
  689.         if cl_object then
  690.             reset_animation(cl_object)
  691.             printf("teleporting npc [%s]", k.id)
  692.             cl_object:set_npc_position(position)
  693.             printf("end of teleporting npc [%s]", k.id)
  694.         else
  695.             k.object.position = position
  696.         end
  697.     end
  698. end
  699.  
  700. function sim_squad_scripted:has_detector()
  701.     for k in self:squad_members() do
  702.         if alife():object(k.id) and  alife():object(k.id):has_detector() then
  703.             return true
  704.         end
  705.     end
  706.     return false
  707. end
  708.  
  709. function sim_squad_scripted:get_squad_community()
  710.     local squad_community = squad_community_by_behaviour[self.player_id]
  711.     if squad_community == nil then
  712.         abort("squad community is 'nil' for player_id [%s]", self.player_id)
  713.     end
  714.     return squad_community
  715. end
  716.  
  717. --***********************************************************************************************
  718. --*                                     SAVE\LOAD                                               *
  719. --***********************************************************************************************
  720.  
  721. function sim_squad_scripted:STATE_Write(packet)
  722.     cse_alife_online_offline_group.STATE_Write (self, packet)
  723.     set_save_marker(packet, "save", false, "sim_squad_scripted")
  724.  
  725.  
  726.     packet:w_stringZ(tostring(self.current_target_id))
  727.     packet:w_stringZ(tostring(self.respawn_point_id))
  728.     packet:w_stringZ(tostring(self.respawn_point_prop_section))
  729.     packet:w_stringZ(tostring(self.smart_id))
  730.  
  731.     set_save_marker(packet, "save", true, "sim_squad_scripted")
  732. end
  733. function sim_squad_scripted:STATE_Read(packet, size)
  734.     cse_alife_online_offline_group.STATE_Read (self, packet, size)
  735.     set_save_marker(packet, "load", false, "sim_squad_scripted")
  736.  
  737.     self.current_target_id = packet:r_stringZ()
  738.     if self.current_target_id == "nil" then
  739.         self.current_target_id = nil
  740.     else
  741.         self.current_target_id = tonumber(self.current_target_id)
  742.     end
  743.     self.respawn_point_id = packet:r_stringZ()
  744.     if self.respawn_point_id == "nil" then
  745.         self.respawn_point_id = nil
  746.     else
  747.         self.respawn_point_id = tonumber(self.respawn_point_id)
  748.     end
  749.     self.respawn_point_prop_section = packet:r_stringZ()
  750.     if self.respawn_point_prop_section == "nil" then
  751.         self.respawn_point_prop_section = nil
  752.     end
  753.     self.smart_id = packet:r_stringZ()
  754.     if self.smart_id == "nil" then
  755.         self.smart_id = nil
  756.     else
  757.         self.smart_id = tonumber(self.smart_id)
  758.     end
  759.  
  760.     self:init_squad_on_load()
  761.     set_save_marker(packet, "load", true, "sim_squad_scripted")
  762. end
  763. --***********************************************************************************************
  764. --*                                     SERVER_OBJECT                                           *
  765. --***********************************************************************************************
  766.  
  767. function sim_squad_scripted:on_register()
  768.     cse_alife_online_offline_group.on_register( self )
  769.     self.board.squads[self.id] = self
  770.     -- Ïðîâåðÿåì êàñòîìäàòó îáüåêòà íà íàëè÷èå ñòîðè àéäè.
  771.     story_objects.check_spawn_ini_for_story_id(self)
  772.     simulation_objects.get_sim_obj_registry():register(self)
  773. end
  774. function sim_squad_scripted:on_unregister()
  775.     --' Îòðåãèñòðàöèÿ â òàñêìåíåäæåðå
  776.     unregister_story_object_by_id(self.id)
  777.         --' Óäàëèòü îòðÿä
  778.     self.board.squads[self.id] = nil
  779.     self.board:assign_squad_to_smart(self, nil)
  780.     cse_alife_online_offline_group.on_unregister( self )
  781.     simulation_objects.get_sim_obj_registry():unregister(self)
  782.     if self.respawn_point_id ~= nil then
  783.         local smart = alife():object(self.respawn_point_id)
  784.         -- çàòû÷êà äëÿ äåñòðîÿ ëåâåëà(ñìàðòû äåñòðîÿòñÿ ðàíüøå ñêâàäîâ)
  785.         if smart == nil then
  786.             return
  787.         end
  788.         smart.already_spawned[self.respawn_point_prop_section].num = smart.already_spawned[self.respawn_point_prop_section].num - 1
  789.     end
  790. end
  791. function sim_squad_scripted:can_switch_offline()
  792.     return cse_alife_online_offline_group.can_switch_offline(self)
  793. end
  794. function sim_squad_scripted:can_switch_online()
  795.     return cse_alife_online_offline_group.can_switch_online(self)
  796. end
  797. function sim_squad_scripted:switch_offline()
  798.     if rx_ai then
  799.         rx_ai.squad_switch_offline(self)
  800.         return
  801.     end
  802.     cse_alife_online_offline_group.switch_offline(self)
  803. end
  804. function sim_squad_scripted:switch_online()
  805.     if rx_ai then
  806.         rx_ai.squad_switch_online(self)
  807.     end
  808.     cse_alife_online_offline_group.switch_online(self)
  809. end
  810.  
  811. --***********************************************************************************************
  812. --*                                     MAP LOCATION                                            *
  813. --***********************************************************************************************
  814.  
  815. --[[
  816. monster_predatory_day
  817. monster_predatory_night
  818. monster_vegetarian
  819. monster_zombied_day
  820. monster_zombied_night
  821. monster_special
  822. ]]--
  823.  
  824. is_squad_monster =
  825. {
  826.     ["monster_predatory_day"]   = true,
  827.     ["monster_predatory_night"] = true,
  828.     ["monster_vegetarian"]      = true,
  829.     ["monster_zombied_day"]     = true,
  830.     ["monster_zombied_night"]   = true,
  831.     ["monster_special"]         = true,
  832.     ["monster"]                 = true
  833. }
  834.  
  835. function sim_squad_scripted:refresh()
  836.     if(self:commander_id()==nil) then
  837.         self:hide()
  838.         return
  839.     end
  840.     self:show()
  841. end
  842.  
  843.  
  844. function sim_squad_scripted:hide()
  845.     if(self.current_spot_id==nil) or (self.spot_section==nil) then
  846.         return
  847.     end
  848.     level.map_remove_object_spot(self.current_spot_id, self.spot_section)
  849.     self.current_spot_id = nil
  850.     self.spot_section = nil
  851. end
  852.  
  853. --' Ïîêàçàòü îòðÿä íà êàðòå
  854. function sim_squad_scripted:show()
  855.     if self.show_disabled then
  856.         self:hide()
  857.         return
  858.     end
  859.  
  860.     if(level.map_has_object_spot(self:commander_id(), "ui_pda2_trader_location")~=0) or
  861.     (level.map_has_object_spot(self:commander_id(), "ui_pda2_mechanic_location")~=0) or
  862.     (level.map_has_object_spot(self:commander_id(), "ui_pda2_scout_location")~=0) or
  863.     (level.map_has_object_spot(self:commander_id(), "ui_pda2_quest_npc_location")~=0) or
  864.     (level.map_has_object_spot(self:commander_id(), "ui_pda2_medic_location")~=0) then
  865.         self.show_disabled = true
  866.         return
  867.     end
  868.  
  869.     if self.current_spot_id ~= self:commander_id() then
  870.         self:hide()
  871.         self.current_spot_id = self:commander_id()
  872.         self:show()
  873.         return
  874.     end
  875.     local spot = ""
  876.  
  877.     if not(is_squad_monster[self.player_id]) then
  878.         local relation = game_relations.get_squad_relation_to_actor_by_id(self.id)
  879.         if(relation=="friends") then
  880.             spot = "alife_presentation_squad_friend"
  881.         elseif(relation=="neutral") then
  882.             spot = "alife_presentation_squad_neutral"
  883.         end
  884.     end
  885.     if(spot~="") then
  886.         if spot == self.spot_section then
  887.             level.map_change_spot_hint(self.current_spot_id, self.spot_section, self:get_squad_props())
  888.             return
  889.         end
  890.         if self.spot_section == nil then
  891.             level.map_add_object_spot(self.current_spot_id, spot, self:get_squad_props())
  892.         else
  893.             level.map_remove_object_spot(self.current_spot_id, self.spot_section)
  894.             level.map_add_object_spot(self.current_spot_id, spot, self:get_squad_props())
  895.         end
  896.         self.spot_section = spot
  897.     elseif(self.spot_section~=nil) then
  898.         level.map_remove_object_spot(self.current_spot_id, self.spot_section)
  899.         self.spot_section = nil
  900.     end
  901. end
  902.  
  903. function sim_squad_scripted:get_squad_props()
  904.     if dev_debug then
  905.         local t = "["..tostring(self:name()).."]\\n"..
  906.                     "current_target = ["..tostring(self.current_target_id and alife():object(self.current_target_id) and alife():object(self.current_target_id):name()).."]\\n"..
  907.                     "assigned_target = ["..tostring(self.assigned_target_id and alife():object(self.assigned_target_id) and alife():object(self.assigned_target_id):name()).."]\\n"
  908.         if self.current_action and self.current_action.name == "stay_point" then
  909.             t = t.."stay_on_point = ["..tostring(self.current_action.idle_time - game.get_game_time():diffSec(self.current_action.start_time)).."]"
  910.         end
  911.         return t
  912.     else
  913.         return ""
  914.     end
  915. end
  916.  
  917.  
  918.  
  919.  
  920. --***********************************************************************************************
  921. --*                                     SIMULATION_TARGET_SQUAD                                 *
  922. --***********************************************************************************************
  923. -- Ïîëó÷èòü ïîçèöèþ, ëåâåë âåðòåêñ, ãåéì âåðòåêñ îáüåêòà.
  924. function sim_squad_scripted:get_location()
  925.     return self.position, self.m_level_vertex_id, self.m_game_vertex_id
  926. end
  927.  
  928. function sim_squad_scripted:get_current_task()
  929.     if self.assigned_target_id ~= nil and alife():object(self.assigned_target_id) ~= nil then
  930.         local smart_terrain = alife():object(self.assigned_target_id)
  931.         if smart_terrain.arriving_npc ~= nil and smart_terrain.arriving_npc[self:commander_id()] == nil
  932.             and smart_terrain.npc_info and smart_terrain.npc_info[self:commander_id()]
  933.             and smart_terrain.npc_info[self:commander_id()].job_id and smart_terrain.job_data[smart_terrain.npc_info[self:commander_id()].job_id] then
  934.             return smart_terrain.job_data[smart_terrain.npc_info[self:commander_id()].job_id].alife_task
  935.         end
  936.         return alife():object(self.assigned_target_id):get_alife_task()
  937.     end
  938.     return self:get_alife_task()
  939. end
  940. -- Äîñòèãíóò ëè ÿ îòðÿäîì âûáðàâøèì ìåíÿ êàê öåëü.
  941. function sim_squad_scripted:am_i_reached(squad)
  942.     return self:npc_count() == 0
  943. end
  944. -- Âûçûâàåòñÿ 1 ðàç ïîñëå äîñòèæåíèÿ ìåíÿ îòðÿäîì âûáðàâøèì ìåíÿ êàê öåëü.
  945. function sim_squad_scripted:on_after_reach(squad)
  946.  
  947. end
  948. -- Âûçûâàåòñÿ 1 ðàç â ìîìåíò âûáîðà ìåíÿ êàê öåëè.
  949. function sim_squad_scripted:on_reach_target(squad)
  950.     squad:set_location_types()
  951.     for k in squad:squad_members() do
  952.         if db.offline_objects[k.id] ~= nil then
  953.             db.offline_objects[k.id] = {}
  954.         end
  955.     end
  956.     self.board:assign_squad_to_smart(squad, nil)
  957. end
  958. -- Âîçâðàùàåò CALifeSmartTerrainTask íà ìåíÿ, âûçûâàåòñÿ èç smart_terrain:task()
  959. function sim_squad_scripted:get_alife_task()
  960.     --printf("Returning alife task for object [%s] game_vertex [%s] level_vertex [%s] position %s", self.id, self.m_game_vertex_id, self.m_level_vertex_id, vec_to_str(self.position))
  961.     return CALifeSmartTerrainTask(self.m_game_vertex_id, self.m_level_vertex_id)
  962. end
  963.  
  964. local smarts_by_no_assault_zones = {
  965.                                     ["zat_a2_sr_no_assault"]    = "zat_stalker_base_smart",
  966.                                     ["jup_a6_sr_no_assault"]    = "jup_a6",
  967.                                     ["jup_b41_sr_no_assault"]   = "jup_b41"
  968. }
  969.  
  970. function sim_squad_scripted:sim_available()
  971.     for k,v in pairs (smarts_by_no_assault_zones) do
  972.         local zone = db.zone_by_name[k]
  973.         if zone and zone:inside(self.position) then
  974.             local smart = sim_board.get_sim_board():get_smart_by_name(v)
  975.             if smart and smart.base_on_actor_control ~= nil and smart.base_on_actor_control.status ~= smart_terrain_control.ALARM then
  976.                 return false
  977.             end
  978.         end
  979.     end
  980.  
  981.     if self.smart_id == nil then
  982.         return true
  983.     end
  984.     -- Óäàëÿòü èç ðåãèñòðà ñèì îáüåêòîâ åñëè ìû èäåì íà áàçó.
  985.     local props_base = alife():object(self.smart_id).props and alife():object(self.smart_id).props["base"]
  986.     if props_base and tonumber(props_base) > 0 then
  987.         return false
  988.     end
  989.  
  990.  
  991.     local smart = alife():object(self.smart_id)
  992.     if smart.base_on_actor_control ~= nil and smart.base_on_actor_control.status ~= smart_terrain_control.NORMAL then
  993.         if db.zone_by_name[smart.base_on_actor_control.noweap_zone] == nil or not db.zone_by_name[smart.base_on_actor_control.noweap_zone]:inside(self.position) then
  994.             return false
  995.         end
  996.     end
  997.     return true
  998. end
  999.  
  1000. -- Ìîé ïðåêîíäèøí.
  1001. function sim_squad_scripted:target_precondition(squad)
  1002.     local squad_params = sim_board.simulation_activities[squad.player_id]
  1003.     if squad_params == nil or squad_params.squad == nil then
  1004.         return false
  1005.     end
  1006.  
  1007.     local self_params = squad_params.squad[self.player_id]
  1008.     if self_params == nil or self_params.prec(squad, self) == false then
  1009.         return false
  1010.     end
  1011.     return true
  1012.  
  1013. --[[
  1014.     if squad.player_id == "dolg" and
  1015.         (is_squad_monster[self.player_id] or self.player_id == "freedom") and
  1016.         in_time_interval(8,22) then
  1017.         return true
  1018.     end
  1019.  
  1020.  
  1021.     if squad.player_id == "bandit" and self.player_id == "stalker" then
  1022.         return true
  1023.     end
  1024.     if squad.player_id == "freedom" and self.player_id == "dolg" and in_time_interval(8,22) then
  1025.         return true
  1026.     end
  1027.  
  1028.     -- Òðàâîÿäíûå äíåì àòàêóþò ïðîõîäÿùèõ ìèìî ñòàëêåðîâ.(ïëîòü, êàáàí)
  1029.     if squad.player_id == "monster_vegetarian" and in_time_interval(8,22) and not is_squad_monster[self.player_id] then
  1030.         return true
  1031.     end
  1032.  
  1033.     -- Õèùíèêè äíåì àòàêóþò ñòàëêåðîâ è òðàâîÿäíûõ(ñîáàêè, ïñåâäîñîáàêè, ïñè ñîáàêè)
  1034.     if squad.player_id == "monster_predatory_day" and
  1035.         in_time_interval(8,22) and
  1036.         (self.player_id == "monster_vegetarian" or not is_squad_monster[self.player_id]) then
  1037.         return true
  1038.     end
  1039.     -- Õèùíèêè íî÷üþ àòàêóþò ñòàëêåðîâ è òðàâîÿäíûõ(òóøêàíû,êðîâîñîñ, õèìåðà)
  1040.     if squad.player_id == "monster_predatory_night" and
  1041.         in_time_interval( 22 , 8) and
  1042.         (self.player_id == "monster_vegetarian" or not is_squad_monster[self.player_id]) then
  1043.         return true
  1044.     end
  1045.     -- Çîìáèîáðàçíûå äíåì àòàêóþò ïðîõîäÿùèõ ìèìî ñòàëêåðîâ.
  1046.     if squad.player_id == "monster_zombied_day" and
  1047.         in_time_interval(8,22) and
  1048.         (not is_squad_monster[self.player_id]) then
  1049.         return true
  1050.     end
  1051.     -- Çîìáèîáðàçíûå äíåì àòàêóþò ïðîõîäÿùèõ ìèìî ñòàëêåðîâ.
  1052.     if squad.player_id == "monster_zombied_night" and
  1053.         in_time_interval(22,8) and
  1054.         (not is_squad_monster[self.player_id]) then
  1055.         return true
  1056.     end
  1057.     -- Îñîáåííûå äíåì àòàêóþò ïðîõîäÿùèõ ìèìî ñòàëêåðîâ.
  1058.     if squad.player_id == "monster_special" and
  1059.         in_time_interval(8,22) and
  1060.         (not is_squad_monster[self.player_id]) then
  1061.         return true
  1062.     end
  1063.  
  1064.     return false
  1065.     ]]
  1066. end
  1067.  
  1068. -- Ïîñ÷èòàòü ìîé ïðèîðèòåò äëÿ îòðÿäà.
  1069. function sim_squad_scripted:evaluate_prior(squad)
  1070.     return simulation_objects.evaluate_prior(self, squad)
  1071. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement