Obrażenia zadawane przez ogniska

Regulamin forum
Dział "Tworzenie Modyfikacji" służy do zadawania pytań odnośnie tworzenia modyfikacji, edytowania plików gry, oraz pisania tzw. tutoriali, czyli poradników odnośnie modyfikowania gry.
Nie zadajemy tutaj pytań odnośnie modyfikacji gotowych (nie dyskutujemy o nich!), prócz prób ich połączenia etc.


Przy cytowaniu plików *.LTX stosować tag [SYNTAX="ini"], przy cytowaniu plików *.script [SYNTAX="lua"] a przy cytowaniu plików *.xml - [SYNTAX="xml"].

Obrażenia zadawane przez ogniska

Postprzez max1071 w 04 Gru 2016, 17:53

Witajcie.

Mam problem i potrzebuję moda na to by wyłączyć zadawanie obrażeń przez ogniska..
Awatar użytkownika
max1071
Stalker

Posty: 135
Dołączenie: 04 Gru 2010, 13:07
Ostatnio był: 09 Cze 2023, 20:21
Frakcja: Wolność
Ulubiona broń: TRs 301
Kozaki: 23

Reklamy Google

Re: Obrażenia zadawane przez ogniska

Postprzez Poldzer w 05 Gru 2016, 13:08

Gdzieś kiedyś mi się migło, że ogniska są w plikach razem z anomaliami, ale jak to dokłanie było to nie pamiętam.
Awatar użytkownika
Poldzer
Legenda

Posty: 1014
Dołączenie: 02 Paź 2013, 17:17
Ostatnio był: 06 Sty 2023, 13:41
Frakcja: Powinność
Ulubiona broń: SPSA14
Kozaki: 239

Re: Obrażenia zadawane przez ogniska

Postprzez max1071 w 06 Gru 2016, 09:26

okej poszukam i dam znać jak to mi wyszło..

--------------------- edit 1 ------------

szukam szukam i nie mogę znaleźć

może możliwe jest po protu przesunięcie spawnu stalkerów od ogniska o np 2 (dwa) metry ??

------------- edit 2 -------------

znalazłem coś na jakimś forum że za ogniska odpowiada ten plik In gamedata\config\misc\zone_kampfire.ltx
załączam go tutaj
Kod: Zaznacz wszystko
[zone_campfire_mp_nolight]
GroupControlSection         = spawn_group_zone
$spawn                   = "zones\campfire_mp_nolight"
$prefetch                = 16
class                  = Z_MBALD

hit_impulse_scale         = 0.00
effective_radius         = 1.3 ;размер радиуса в процентах от оригинального, где действует зона

ef_anomaly_type            = 1
ef_weapon_type            = 13

sound                  =
postprocess               = postprocess_flame
   
artefacts               =
BirthProbability          = 0.0

;----------- Anomaly settings -----------------------
min_start_power      = 0.99
max_start_power      = 1.00
attenuation         = 1
period            = 1
min_artefact_count   = 0
max_artefact_count   = 0

idle_particles            = explosions\campfire_05
blowout_particles         = explosions\campfire_blowout

hit_small_particles         = damage_fx\burn_creatures00
hit_big_particles         = damage_fx\burn_creatures00

idle_small_particles      = damage_fx\burn_creatures00
idle_big_particles         = damage_fx\burn_creatures00

idle_particles_dont_stop   = true;

idle_sound               = ambient\fire2      ;постоянный звук
blowout_sound            = ambient\fire2      ;во время выброса(удара) в центре аномалии   
hit_sound               = ambient\fire2      ;на персонаже, когда тот получает хит
entrance_sound            = ambient\fire2      ;при попадании объекта в аномалию

hit_type               = burn

disable_time            = 10000   ;время игнорирования неживого объекта в зоне (-1 если не нужно)
disable_time_small         = -1   ;время игнорирования маленького неживого объекта в зоне (-1 если не нужно)
disable_idle_time         = 50000   ;время отключения idle партиклов

ignore_nonalive            = false
ignore_small            = true
ignore_artefacts         = true

blowout_light            = on
light_color                = 1.8,1.7,1.4
light_animation             = koster
light_range                = 4
light_time                 = 0.35
light_height            = 0.75         ;подъем источника света на высоту


idle_light               = off
idle_light_range         = 8.0
idle_light_range_delta       = 0.25
idle_light_anim            = koster_00
idle_light_height         = 0.70         ;подъем источника света на высоту

awaking_time            = 0
blowout_time            = 1000   
accamulate_time            = 0

visible_by_detector       = off

blowout_wind            = off

blowout_wind_time_start    = 0
blowout_wind_time_peak     = 600
blowout_wind_time_end      = 899
blowout_wind_power         = 0.5         ;сила поднимаего ветра (от 0 до 1), в момент blowout_wind_time_peak

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;рождение артефактов во время срабатывания
spawn_blowout_artefacts = off



[zone_campfire_grill]
GroupControlSection         = spawn_group_zone
$spawn                   = "zones\campfire_grill"
$prefetch                = 16
class                  = Z_MBALD

hit_impulse_scale         = 0.00
effective_radius         = 1.0 ;размер радиуса в процентах от оригинального, где действует зона

ef_anomaly_type            = 1
ef_weapon_type            = 13

sound                  =
postprocess               = postprocess_flame
   
artefacts               =
BirthProbability          = 0.0

;----------- Anomaly settings -----------------------
min_start_power      = 0.39
max_start_power      = 0.40
attenuation         = 1
period            = 1
min_artefact_count   = 0
max_artefact_count   = 0

idle_particles            = explosions\campfire_boar_grill
blowout_particles         = explosions\campfire_blowout

hit_small_particles         = damage_fx\burn_creatures00
hit_big_particles         = damage_fx\burn_creatures00
idle_small_particles      = damage_fx\burn_creatures00
idle_big_particles         = damage_fx\burn_creatures00

idle_particles_dont_stop   = true;

idle_sound               = ambient\fire2      ;постоянный звук
blowout_sound            = ambient\fire2      ;во время выброса(удара) в центре аномалии   
hit_sound               = ambient\fire2      ;на персонаже, когда тот получает хит
entrance_sound            = ambient\fire2      ;при попадании объекта в аномалию

hit_type               = burn

disable_time            = 10000   ;время игнорирования неживого объекта в зоне (-1 если не нужно)
disable_time_small         = -1   ;время игнорирования маленького неживого объекта в зоне (-1 если не нужно)
disable_idle_time         = 50000   ;время отключения idle партиклов

ignore_nonalive            = false
ignore_small            = true
ignore_artefacts         = true

blowout_light            = off
light_color                = 1.8,1.7,1.4
light_animation             = koster
light_range                = 8
light_time                 = 0.35
light_height            = 0.35         ;подъем источника света на высоту


idle_light               = off
idle_light_range         = 8.0
idle_light_range_delta       = 0.25
idle_light_anim            = koster_00
idle_light_height         = 0.70         ;подъем источника света на высоту

awaking_time            = 500
blowout_time            = 1000   
accamulate_time            = 0

visible_by_detector       = off

blowout_wind            = off

blowout_wind_time_start    = 0
blowout_wind_time_peak     = 600
blowout_wind_time_end      = 899
blowout_wind_power         = 0.5         ;сила поднимаего ветра (от 0 до 1), в момент blowout_wind_time_peak

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;рождение артефактов во время срабатывания
spawn_blowout_artefacts = off



[zone_flame]
GroupControlSection   = spawn_group_zone
$spawn          = "zones\flame"
$prefetch       = 16
class         = Z_MBALD
hit_impulse_scale   = 0.0
effective_radius   = 1.3 ;размер радиуса в процентах от оригинального, где действует зона
sound         = zone_mosquito_bald
postprocess      = postprocess_flame

ef_anomaly_type         = 1
ef_weapon_type         = 13

artefacts      =
BirthProbability = 0.0

;----------- Anomaly settings -----------------------
min_start_power      = 0.39
max_start_power      = 0.40
attenuation         = 1
period            = 1
min_artefact_count   = 0
max_artefact_count   = 0

idle_particles      = explosions\campfire_04
blowout_particles   = explosions\campfire_blowout

hit_small_particles         = damage_fx\burn_creatures
hit_big_particles         = damage_fx\burn_creatures00
idle_small_particles      = damage_fx\burn_creatures
idle_big_particles         = damage_fx\burn_creatures00

idle_particles_dont_stop   = true;

idle_sound         = ambient\fire2                  ;постоянный звук
blowout_sound      = ambient\fire2      ;во время выброса(удара) в центре аномалии   
hit_sound         = ambient\fire2                        ;на персонаже, когда тот получает хит
entrance_sound      = ambient\fire2                           ;при попадании объекта в аномалию

hit_type         = burn

disable_time      = 10000      ;время игнорирования неживого объекта в зоне (-1 если не нужно)
disable_time_small   = -1      ;время игнорирования маленького неживого объекта в зоне (-1 если не нужно)
disable_idle_time   = 50000      ;время отключения idle партиклов

ignore_nonalive      = false
ignore_small      = true
ignore_artefacts   = true

blowout_light      = off
light_color          = 1.8,1.7,1.4
light_range          = 8.0
light_time           = 0.35
light_height      = 0.75         ;подъем источника света на высоту


idle_light         = off
idle_light_range   = 8.0
idle_light_range_delta = 0.2
idle_light_anim      = koster_01
idle_light_height   = 0.70         ;подъем источника света на высоту

awaking_time      = 1000
blowout_time      = 300   
accamulate_time      = 1000

visible_by_detector = off

blowout_wind      = off

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;рождение артефактов во время срабатывания
spawn_blowout_artefacts = off



[zone_zhar]
GroupControlSection   = spawn_group_zone
$spawn          = "zones\zhar"
$prefetch       = 16
class         = Z_MBALD
hit_impulse_scale   = 0.0
effective_radius   = 1.3 ;?acia? ?aaeona a i?ioaioao io i?eaeiaeuiiai, aaa aaenoaoao ciia
sound         = zone_mosquito_bald
postprocess      = postprocess_flame

ef_anomaly_type         = 1
ef_weapon_type         = 13

artefacts      =
BirthProbability = 0.0

;----------- Anomaly settings -----------------------
min_start_power      = 0.39
max_start_power      = 0.40
attenuation         = 1
period            = 1
min_artefact_count   = 0
max_artefact_count   = 0

idle_particles      =
blowout_particles   =

hit_small_particles         = damage_fx\burn_creatures
hit_big_particles         = damage_fx\burn_creatures00
idle_small_particles      = damage_fx\burn_creatures
idle_big_particles         = damage_fx\burn_creatures00

idle_particles_dont_stop   = true;

idle_sound         = ambient\zhar                  ;iinoiyiiue caoe
blowout_sound      = ambient\zhar      ;ai a?aiy aua?ina(oaa?a) a oaio?a aiiiaeee   
hit_sound         = ambient\zhar                        ;ia ia?niia?a, eiaaa oio iieo?aao oeo
entrance_sound      = ambient\zhar                           ;i?e iiiaaaiee iauaeoa a aiiiaee?

hit_type         = burn

disable_time      = 10000      ;a?aiy eaii?e?iaaiey ia?eaiai iauaeoa a ciia (-1 anee ia io?ii)
disable_time_small   = -1      ;a?aiy eaii?e?iaaiey iaeaiueiai ia?eaiai iauaeoa a ciia (-1 anee ia io?ii)
disable_idle_time   = 50000      ;a?aiy ioee??aiey idle ia?oeeeia

ignore_nonalive      = false
ignore_small      = false
ignore_artefacts   = true

blowout_light      = off
light_color          = 1.8,1.7,1.4
light_range          = 8.0
light_time           = 0.35
light_height      = 0.75         ;iiauai enoi?ieea naaoa ia aunioo


idle_light         = off
idle_light_range   = 8.0
idle_light_range_delta = 0.2
idle_light_anim      = koster_01
idle_light_height   = 0.70         ;iiauai enoi?ieea naaoa ia aunioo

awaking_time      = 10
blowout_time      = 50   
accamulate_time      = 10

visible_by_detector = off

blowout_wind      = off

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;?i?aaiea a?oaoaeoia ai a?aiy n?aaaouaaiey
spawn_blowout_artefacts = off



[zone_emi]
GroupControlSection   = spawn_group_zone
$spawn          = "zones\emi"
$prefetch       = 16
class         = Z_MBALD
hit_impulse_scale   = .01
effective_radius   = 1 ;размер радиуса в процентах от оригинального, где действует зона
sound         = zone_mosquito_bald
postprocess      = postprocess_electra

ef_anomaly_type         = 1
ef_weapon_type         = 13

artefacts      =
BirthProbability = 0.0

;----------- Anomaly settings -----------------------
min_start_power      = 0.39
max_start_power      = 0.40
attenuation         = 1
period            = 1
min_artefact_count   = 0
max_artefact_count   = 0

idle_particles      = anomaly2\emi_idle_00
blowout_particles   = anomaly2\tornado_00

hit_small_particles         = hit_fx\hit_metal_02
hit_big_particles         = anomaly2\emi_damage_big_smoke
idle_small_particles      = anomaly2\electra_damage_01_smoke
idle_big_particles         = anomaly2\emi_damage_big_smoke
entrance_small_particles   = anomaly2\electra_entrance_small
entrance_big_particles      = anomaly2\emi_entrance_big_00

idle_sound         = anomaly\emi_idle; anomaly_gravy_idle
blowout_sound      = anomaly\emi_blowout
hit_sound         = anomaly\electra_blast
entrance_sound      = anomaly\emi_entrance

blowout_light      = on
light_color          = 1.4,1.5,1.8
light_range          = 80.0
light_time           = 1;0.35
light_height      = 15         ;подъем источника света на высоту

idle_light         = off

hit_type      = strike

awaking_time      = 0
blowout_time      = 6000   
accamulate_time      = 5000

blowout_light_time      = 5600
blowout_explosion_time   = 5000
blowout_particles_time   = 0
blowout_sound_time     = 0

disable_time      = -1   ;время игнорирования неживого объекта в зоне (-1 если не нужно)
disable_time_small   = 500   ;время игнорирования маленького неживого объекта в зоне (-1 если не нужно)
disable_idle_time   = 1000   ;время отключения idle партиклов

ignore_nonalive      = false
ignore_small      = false
ignore_artefacts   = true

visible_by_detector = on

blowout_wind      = off

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;рождение артефактов во время срабатывания
spawn_blowout_artefacts = off



[zone_flame_small]
GroupControlSection         = spawn_group_zone
$spawn                   = "zones\campfire"
$prefetch                = 16
class                  = Z_MBALD

hit_impulse_scale         = 0.0
effective_radius         = 1.3 ;размер радиуса в процентах от оригинального, где действует зона

ef_anomaly_type            = 1
ef_weapon_type            = 13

sound                  =
postprocess               = postprocess_flame
   
artefacts               =
BirthProbability          = 0.0

;----------- Anomaly settings -----------------------
min_start_power      = 0.39
max_start_power      = 0.40
attenuation         = 1
period            = 1
min_artefact_count   = 0
max_artefact_count   = 0

idle_particles            = explosions\campfire_05
blowout_particles         = explosions\campfire_blowout

hit_small_particles         = damage_fx\burn_creatures00
hit_big_particles         = damage_fx\burn_creatures00
idle_small_particles      = damage_fx\burn_creatures00
idle_big_particles         = damage_fx\burn_creatures00

idle_particles_dont_stop   = true;

idle_sound               = ambient\fire2      ;постоянный звук
blowout_sound            = ambient\fire2      ;во время выброса(удара) в центре аномалии   
hit_sound               = ambient\fire2      ;на персонаже, когда тот получает хит
entrance_sound            = ambient\fire2      ;при попадании объекта в аномалию

hit_type               = burn

disable_time            = 10000   ;время игнорирования неживого объекта в зоне (-1 если не нужно)
disable_time_small         = -1   ;время игнорирования маленького неживого объекта в зоне (-1 если не нужно)
disable_idle_time         = 50000   ;время отключения idle партиклов

ignore_nonalive            = false
ignore_small            = true
ignore_artefacts         = true

blowout_light            = on
light_color                = 1.8,1.7,1.4
light_animation             = koster
light_range                = 8
light_time                 = 0.35
light_height            = 0.75         ;подъем источника света на высоту


idle_light               = off
idle_light_range         = 8.0
idle_light_range_delta       = 0.25
idle_light_anim            = koster_00
idle_light_height         = 0.70         ;подъем источника света на высоту

awaking_time            = 0
blowout_time            = 1000   
accamulate_time            = 0

visible_by_detector       = off

blowout_wind            = off

blowout_wind_time_start    = 0
blowout_wind_time_peak     = 600
blowout_wind_time_end      = 899
blowout_wind_power         = 0.5         ;сила поднимаего ветра (от 0 до 1), в момент blowout_wind_time_peak

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;рождение артефактов во время срабатывания
spawn_blowout_artefacts = off


tylko że ja nawet nie wiem co właściwie edytować by ogniska nie zadawały obrażeń
albo zadawały tylko w małym stopniu..

------- edit 4 -------

można by było zrobić moda który po opuszczeniu danego obozowiska automatycznie by wyłączał to ognisko ?

------ edit 5 ---------

ściągnołem sobie moda na dynamics campfire co prawda na początku dobrze się zapowiadało ..
co prawda automatycznie włącza ogniska na mapie ale ich nie gasi ...
i jak wracam od bazy wolności w magazynach wojskowych koło wilka to go ten płomień z ogniska zabija

próbowałem edytować plik xr_campfire czy jakoś tak ... robiłem robiłem i nic co chwila crash czy coś ....

zaczeło nawet ładnie działać jak zrobiłem czy w danej odległości znajduje się gracz to znaczy obiekty przechodzą w stan online... to wtedy resetowało ognisko w sensie wyłączało z automatu jak byłem od niego na początku 20 nic nie dawało zginoł od razu, 50 to samo, 75 jak dobiegałem to akurat widziałem jak ginie mi na oczach, 125 i tutaj grało ok.. po pięciu(5) sekundach uruchamiało je ponownie.
do czasu jak wracasz z misji zabicia tych z Powinności w gospodarstwie.

załączam tego moda dynamics fire może i on się komuś przyda a nawet wykona mi jakieś zmiany czy jakoś pomoże w tym by ogarnąć te ogniska.
plik:
Kod: Zaznacz wszystko
function init    (obj)
   xr_motivator.AddToMotivator(obj)
end

function actor_init    (npc)
   npc:bind_object(actor_binder(npc))
end

local game_difficulty_by_num = {
   [0] = "gd_novice",
   [1] = "gd_stalker",
   [2] = "gd_veteran",
   [3] = "gd_master"
   }

lasthealth  = 0
lasttime   = 0
post_process = 0
local weapon_hide = false
-->> Dynamic campfire mod
local scan_flag
local upd_time
--<< Dynamic campfire mod
----------------------------------------------------------------------------------------------------------------------
class "actor_binder" (object_binder)
----------------------------------------------------------------------------------------------------------------------
function actor_binder:__init (obj) super(obj)
   self.bCheckStart = false
   self.weather_manager = level_weathers.WeatherManager()
   self.actor_detector = xr_detector.actor_detector()
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:net_spawn(data)
   printf("actor net spawn")      

   level.show_indicators()

   self.bCheckStart = true
   self.weapon_hide = false -- спрятано или нет оружие при разговоре.
   weapon_hide = false -- устанавливаем глобальный дефолтовый флаг.

   if object_binder.net_spawn(self,data) == false then
      return false
   end

   db.add_actor(self.object)
   
   if self.st.disable_input_time == nil then
      level.enable_input()
   end

   self.weather_manager:reset()
--   game_stats.initialize ()

   if(actor_stats.add_to_ranking~=nil)then
      actor_stats.add_to_ranking(self.object:id())
   end

   --' Загружаем настройки дропа
   death_manager.init_drop_settings()

   return true
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:net_destroy()
   if(actor_stats.remove_from_ranking~=nil)then
      actor_stats.remove_from_ranking(self.object:id())
   end
--   game_stats.shutdown ()
   db.del_actor(self.object)

    sr_light.clean_up ()

   self.object:set_callback(callback.inventory_info, nil)
   self.object:set_callback(callback.article_info, nil)
   self.object:set_callback(callback.on_item_take, nil)
   self.object:set_callback(callback.on_item_drop, nil)
   --self.object:set_callback(callback.actor_sleep, nil)
   self.object:set_callback(callback.task_state, nil)
   self.object:set_callback(callback.level_border_enter, nil)
   self.object:set_callback(callback.level_border_exit, nil)
   self.object:set_callback(callback.take_item_from_box, nil)

   if sr_psy_antenna.psy_antenna then
      sr_psy_antenna.psy_antenna:destroy()
      sr_psy_antenna.psy_antenna = false
   end

   xr_sound.stop_all_sound_object()

   object_binder.net_destroy(self)
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:reinit()
   object_binder.reinit(self)
   
   local npc_id = self.object:id()

   db.storage[npc_id] = { }

   self.st = db.storage[npc_id]
   self.st.pstor = nil

   self.next_restrictors_update_time = -10000

   self.object:set_callback(callback.inventory_info, self.info_callback, self)
   self.object:set_callback(callback.article_info, self.article_callback, self)
   self.object:set_callback(callback.on_item_take, self.on_item_take, self)
   self.object:set_callback(callback.on_item_drop, self.on_item_drop, self)
   self.object:set_callback(callback.trade_sell_buy_item, self.on_trade, self) -- for game stats
   --self.object:set_callback(callback.actor_sleep, self.sleep_callback, self)
   self.object:set_callback(callback.task_state, self.task_callback, self)
   --self.object:set_callback(callback.map_location_added, self.map_location_added_callback, self)
   self.object:set_callback(callback.level_border_enter, self.level_border_enter, self)
   self.object:set_callback(callback.level_border_exit, self.level_border_exit, self)
   self.object:set_callback(callback.take_item_from_box, self.take_item_from_box, self)
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:take_item_from_box(box, item)
   local story_id = box:story_id()
   if story_id == nil then
      return
   end

   treasure_manager.take_item_from_box(box, story_id)
--[[   
   local respawner = se_respawn.get_respawner_by_parent(story_id)
   if respawner == nil then
      return
   end
   
   --' Необходимо уменьшить счетчик в респавнере
   respawner:remove_spawned(item:id())

   local smart_terrain = db.strn_by_respawn[respawner:name()]
   if smart_terrain == nil then
      return
   end

   local npc = smart_terrain.gulag:get_nearest_online_obj(db.actor:position())
    if npc ~= nil then
       xr_sound.set_sound_play(npc, "reac_box")
       xr_gulag.setGulagEnemy(smart_terrain:name() , db.actor)      
    end
]]
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:level_border_enter(npc, info_id)
   self.actor_detector:actor_enter()
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:level_border_exit(npc, info_id)
   self.actor_detector:actor_exit()
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:info_callback(npc, info_id)
   printf("*INFO*: npc='%s' id='%s'", npc:name(), info_id)
   --' Сюжет
   level_tasks.proceed(self.object)
   -- Отметки на карте
   level_tasks.process_info_portion(info_id)
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:on_trade (item, sell_bye, money)
    if sell_bye == true then
       game_stats.money_trade_update (money)
    else       
       game_stats.money_trade_update (-money)
    end   
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:article_callback(npc, group, name)
   --printf("article_callback [%s][%s]", group, name)
   if device().precache_frame >1 then return end
   
   if group == "Diary" then
      news_manager.send_encyclopedy("diary", group)
   else
      news_manager.send_encyclopedy("encyclopedy", group)
   end
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:on_item_take (obj)
    level_tasks.proceed(self.object)
    --game_stats.update_take_item (obj, self.object)
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:on_item_drop (obj)
    level_tasks.proceed(self.object)
    --game_stats.update_drop_item (obj, self.object)
end
----------------------------------------------------------------------------------------------------------------------

function actor_binder:task_callback(_task, _objective, _state)
   task_manager.task_callback(_task:get_id(), _objective:get_idx(), _state)
   if _objective:get_idx() == 0 then
      if _state == task.fail then
         news_manager.send_task(db.actor, "fail", _task, _objective)
      elseif _state == task.completed then
         task_manager.reward_by_task(_task)
         news_manager.send_task(db.actor, "complete", _task, _objective)
      else
         news_manager.send_task(db.actor, "new", _task, _objective)
      end
   else
      if _task:get_objective(0):get_state() == task.in_progress then
         news_manager.send_task(db.actor, "update", _task, _objective)
      end
   end
end

----------------------------------------------------------------------------------------------------------------------
function actor_binder:map_location_added_callback(spot_type_str, object_id)
   if (false==app_ready()) or (device().precache_frame>1) then return end
   --'news_manager.send_task(db.actor, "new")
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:update(delta)
   object_binder.update(self, delta)

   -- DEBUG slowdown
--   slowdown.update()

   local time = time_global()
   
   game_stats.update (delta, self.object)

   -- апдейт погоды
   self.weather_manager:update()
   
   -- апдейт схемы детектора
   self.actor_detector:update()

   -- апдейт звуковой схемы актера
   xr_sound.update_actor()
   
   --' Проверка потери жизни
--[[
   if self.object.health - lasthealth > 0.001 or
      self.object.health - lasthealth < -0.001 then
      printf("%f | %f", self.object.health, self.object.health - lasthealth, game.time() - lasttime)
      lasthealth = self.object.health
      lasttime = game.time()
   end
]]   
   -- Обновление отключения ввода с клавиатуры.
   if self.st.disable_input_time ~= nil and
      game.get_game_time():diffSec(self.st.disable_input_time) >= self.st.disable_input_idle
   then
      level.enable_input()
      self.st.disable_input_time = nil
   end
   -- Обновление сна с переносом чувака в указанную позицию
   if self.st.sleep_relocate_time ~= nil and
      game.get_game_time():diffSec(self.st.sleep_relocate_time) >= self.st.sleep_relocate_idle
   then
      self.object:set_actor_position(self.st.sleep_relocate_point)
      local dir = self.st.sleep_relocate_point:sub(self.st.sleep_relocate_look)
      self.object:set_actor_direction(dir:getH())
      self.st.sleep_relocate_time = nil
   end

   -- Апдейт прятание оружия игрока во время диалога
   if weapon_hide == true or self.object:is_talking() then
      if self.weapon_hide == false then
         self.object:hide_weapon()
         self.weapon_hide = true
      end
   else
      if self.weapon_hide == true then
         self.object:restore_weapon()
         self.weapon_hide = false
      end
   end   

   -- обновление рестрикторов, которые под логикой, срабатывает через интервалы времени
   if self.next_restrictors_update_time < time then
      bind_restrictor.actor_update(delta)

      self.next_restrictors_update_time = time + 200

      task_manager.actor_update()
   end

   -- обновление постпроцессов
   if post_process ~= 0 then
      if post_process:update () == true then
         post_process = 0
      end
   end

   -- обновление пси-антенны
   if sr_psy_antenna.psy_antenna then
      sr_psy_antenna.psy_antenna:update(delta)
   end

   --' Вывод сообщения о большой радиации
   if self.object.radiation >= 0.7 then
      local hud = get_hud()
      local custom_static = hud:GetCustomStatic("cs_radiation_danger")
      if custom_static == nil then
         hud:AddCustomStatic("cs_radiation_danger", true)
         hud:GetCustomStatic("cs_radiation_danger"):wnd():SetTextST("st_radiation_danger")
      end
   else
      local hud = get_hud()
      local custom_static = hud:GetCustomStatic("cs_radiation_danger")
      if custom_static ~= nil then
         hud:RemoveCustomStatic("cs_radiation_danger")
      end
   end



    if self.bCheckStart then
      printf("SET DEFAULT INFOS")      

      if not has_alife_info("storyline_actor_start") and
         (level.name() == "l01_escape")
      then
         self.object:give_info_portion("storyline_actor_start")
         _G.g_start_avi = true
         printf("*AVI* RUN START AVI")         
      end

--      if not has_alife_info("encyclopedy") then
--         self.object:give_info_portion("encyclopedy")
--      end

      if not has_alife_info("global_dialogs") then
         self.object:give_info_portion("global_dialogs")
      end

      if not has_alife_info("level_changer_icons") then
         self.object:give_info_portion("level_changer_icons")
      end

      level_tasks.add_lchanger_location()

      self.bCheckStart = false      
   end      
   -->> Dynamic campfire mod
   if scan_flag == nil then
      scan_flag = 1
      local lvl = level.name()
      local exc_tbl = {
         ["zone_flame_small_0002"] = {"l05_bar"},
         ["zone_flame_small_0005"] = {"l06_rostok"},
         ["zone_flame_small_0006"] = {"l06_rostok"},
         ["zone_flame_small_0007"] = {"l06_rostok"},
         ["zone_flame_small_0008"] = {"l06_rostok"},
         ["zone_flame_small_0010"] = {"l06_rostok"},
         ["zone_flame_small_0012"] = {"l11_pripyat"},
         ["zone_flame_small_0013"] = {"l11_pripyat"},
         ["zone_flame_small_0024"] = {"l11_pripyat"},
         ["zone_flame_small_0025"] = {"l11_pripyat"},
         ["lights_camp_fire_omni_r1_r2_0002"] = {"l05_bar"},
         ["lights_camp_fire_omni_r1_r2_0011"] = {"l11_pripyat"},
         ["lights_camp_fire_omni_r1_r2_0012"] = {"l11_pripyat"},
         ["lights_camp_fire_omni_r1_r2_0031"] = {"l08_yantar"}
--         МОЖЕТ БЫТЬ ТАК:   ["zone_flame_small_9999"] = {"l01_escapel02_garbagel05_barl07_military"},
--         МОЖЕТ БЫТЬ ТАК:   ["lights_camp_fire_omni_r1_r2_9999"] = {"l01_escapel02_garbagel05_barl07_military"}
      }
      for id=1, 65535 do
         local obj = level.object_by_id(id)
         if obj then
            local name = obj:name()
            local exc_obj = exc_tbl[name]
            if exc_obj and string.find(exc_obj[1], lvl) then
--               printf("EXEPTIONS: OBJ:[%s] LEVELS:[%s]", name, exc_obj[1])
            else
               if obj:section() == "zone_flame_small" then
                  table.insert(xr_kamp.lvl_objs, obj)
                  obj:disable_anomaly()
               elseif string.find(name, "r1_r2") then
                  table.insert(xr_kamp.lvl_objs, obj)
                  obj:get_hanging_lamp():turn_off()
               -- Масляные горелки (требуется доп. правка particles.xr)
--               elseif string.find(name, "light_gas") then
--                  obj:get_hanging_lamp():turn_off()
               end
            end
         end
      end
   end
   if upd_time == nil then
      upd_time = time + 10000
   elseif upd_time < time then
      upd_time = time + 10000
      xr_kamp.update(time)
   end
   --<< Dynamic campfire mod
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:save(packet)
   
   local save_treasure_manager = true
   
   printf("actor_binder:save(): self.object:name()='%s'", self.object:name())
   object_binder.save(self, packet)

   --' Сохраняем уровень сложности
   if save_treasure_manager == true then
      packet:w_u8(level.get_game_difficulty() + 128)
   else
      packet:w_u8(level.get_game_difficulty())
   end


   --' Сохраняем данные об отключенном вводе
   if self.st.disable_input_time == nil then
      packet:w_bool(false)
   else
      packer:w_bool(true)
      utils.w_CTime(packet, self.st.disable_input_time)
   end

   xr_logic.pstor_save_all(self.object, packet)
   self.weather_manager:save(packet)

   sr_psy_antenna.save( packet )
   
   if save_treasure_manager == true then
      treasure_manager.save(packet)     
   end                                 

   task_manager.save(packet)
   self.actor_detector:save(packet)   
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:load(reader)
   printf("actor_binder:load(): self.object:name()='%s'", self.object:name())
   object_binder.load(self, reader)
   printf("actor_binder:object_binder.load(): self.object:name()='%s'", self.object:name())

   --' Загружаем уровень сложности
   local game_difficulty = reader:r_u8()
   
   local load_treasure_manager = false     
   if game_difficulty >= 128 then           
      game_difficulty = game_difficulty - 128
      load_treasure_manager = true           
   end                                     

   
   get_console():execute("g_game_difficulty "..game_difficulty_by_num[game_difficulty])

   if reader:r_eof() then
      abort("SAVE FILE IS CORRUPT")
   end

   local stored_input_time = reader:r_u8()
   if stored_input_time == true then
      self.st.disable_input_time = utils.r_CTime(reader)
   end

   xr_logic.pstor_load_all(self.object, reader)
   self.weather_manager:load(reader)

   sr_psy_antenna.load(reader)
   
   if load_treasure_manager == true then
      treasure_manager.load(reader)     
   end                                 

   
   task_manager.load(reader)
   self.actor_detector:load(reader)   
end
----------------------------------------------------------------------------------------------------------------------

--старт префетча звуков
--if string.find(command_line(), "-noprefetch") == nil then
--   sound_prefetch.prefetch_sounds()
--end


-- Weapon functions
function hide_weapon()
   weapon_hide = true
end
function restore_weapon()
   weapon_hide = false
end

// this is test for section iteration
/**
local function test_section_iteration(file_name, section_name)
   printf         ("file    : %s",file_name)
   printf         ("section : %s",section_name)
   
   local         file = ini_file(file_name)
   local         n = file:line_count(section_name)
   printf         ("lines   : %d",n)
   
   local         id, value = "", "", result
   for i=0,n-1 do
      result, id, value   = file:r_line(section_name,i,"","")
      printf      ("line %d : %s = %s",i,id,value)
   end
end

test_section_iteration("system.ltx","space_restrictor")
/**/[/spoiler]

plik:[spoiler=xr_campfire.script]----------------------------------------------------------------------------------------------------------------------
--   Схема лагерь. Чудак(и) у костра.
--   автор: Диденко Руслан (Stohe)
--   TODO:
----------------------------------------------------------------------------------------------------------------------
function printf(fmt, ...)
--   local msg = string.format(fmt, ...)
--   local msg_no_ws = string.gsub(msg, "%s", "_")
--   get_console():execute("dbg:" .. msg_no_ws)
end

kamps = {}
kamp_stalkers = {} -- могут ли сталкеры в лагере юзаться игроком.
-- Объявления итераторов
local k,v,kk,vv = 0,0,0,0
---------------------------------------------------------------------------------------------------------------------
--Evaluators
----------------------------------------------------------------------------------------------------------------------
--' Условие завершения скрипта
class "evaluator_kamp_end" (property_evaluator)
function evaluator_kamp_end:__init(name, storage) super (nil, name)
   self.a = storage
end
function evaluator_kamp_end:evaluate()
   return not xr_logic.is_active(self.object, self.a)
end
--' Находимся ли мы на заданной позиции
class "evaluator_on_position" (property_evaluator)
function evaluator_on_position:__init(name, storage) super (nil, name)
   self.a = storage
end
function evaluator_on_position:evaluate()
    if self.object:level_vertex_id() == self.a.pos_vertex then
      return true
   end
   return false
end
----------------------------------------------------------------------------------------------------------------------
--Actions
----------------------------------------------------------------------------------------------------------------------
--' Идет в заданную область
class "action_go_position" (action_base)
function action_go_position:__init (npc_name,action_name,storage) super (nil,action_name)
   self.a = storage
end
function action_go_position:initialize()
   action_base.initialize(self)
--   self.object:set_node_evaluator()
--   self.object:set_path_evaluator()
   self.object:set_desired_position()
   self.object:set_desired_direction()
   
   self.a.pos_vertex = nil
end
function action_go_position:execute ()
   action_base.execute (self)

   if db.actor then
      if xr_logic.try_switch_to_another_section(self.object, self.a, db.actor) then
         return
      end
   end   
   
   local tmp_pos_vertex = kamps[self.a.center_point]:getDestVertex(self.object:id(), self.a.radius)
   if self.a.pos_vertex ~= tmp_pos_vertex then
      self.a.pos_vertex = tmp_pos_vertex
      
      if not self.object:accessible(self.a.pos_vertex) then
         --'printf("[%s] KAMP NODE NOT ACCESSIBLE. Get accessible nearest", self.object:name())
         local ttp = vector():set(0,0,0)
         self.a.pos_vertex = self.object:accessible_nearest(level.vertex_position(self.a.pos_vertex), ttp)
      end
      
      self.a.pp = patrol(self.a.center_point):level_vertex_id(0)
      self.a.pp = level.vertex_in_direction(self.a.pp, vector():set(math.random(-1,1), 0, math.random(-1,1)), math.random(0,0.5))
      self.object:set_dest_level_vertex_id(self.a.pos_vertex)
      self.object:set_desired_direction(vector():sub(level.vertex_position(self.a.pp),level.vertex_position(self.a.pos_vertex)))
      self.object:set_path_type(game_object.level_path)
      state_mgr.set_state(self.object, self.a.def_state_moving)
   end
end
function action_go_position:finalize ()
   action_base.finalize (self)
end

--' Просто сидит и втыкает
class "action_wait" (action_base)
function action_wait:__init (npc_name,action_name,storage) super (nil,action_name)
   self.a = storage
end
function action_wait:initialize()
   action_base.initialize(self)
--   self.object:set_node_evaluator()
--   self.object:set_path_evaluator()
   self.object:set_desired_position()
   self.object:set_desired_direction()
   
   kamps[self.a.center_point]:increasePops(self.object)
end
function action_wait:activate_scheme()
end
function action_wait:execute()
   action_base.execute (self)
   if db.actor then
      if xr_logic.try_switch_to_another_section(self.object, self.a, db.actor) then
         return
      end
   end
   local state, sound, substate = kamps[self.a.center_point]:updateNpc(self.object)
   
   --' повернуть его лицом к центру
   state_mgr.set_state(self.object, state, nil, nil, {look_position = level.vertex_position(self.a.pp)}, nil, nil, {subanim = substate})
   xr_sound.set_sound(self.object, sound)
end
function action_wait:finalize()
   kamps[self.a.center_point]:decreasePops(self.object)
   action_base.finalize (self)
end
function action_wait:deactivate(npc)
   kamps[self.a.center_point]:removeNpc(npc)
end
function action_wait:death_callback(npc)
   kamps[self.a.center_point]:removeNpc(npc)
end
function action_wait:net_destroy(npc)
   kamps[self.a.center_point]:decreasePops(self.object)   --<< Dynamic campfire mod
   kamps[self.a.center_point]:removeNpc(npc)
end


class "CKampManager"
function CKampManager:__init(path)
   self.kamp_name = path
   self.patrol = patrol(path)
   self.center = self.patrol:level_vertex_id(0)
   self.position = {{dir = vector():set(1, 0, 0),   used = nil},
                {dir = vector():set(1, 0, 1),   used = nil},
                {dir = vector():set(0, 0, 1),   used = nil},
                {dir = vector():set(-1, 0, 1),   used = nil},
                {dir = vector():set(-1, 0, 0),   used = nil},
                {dir = vector():set(-1, 0, -1),used = nil},
                {dir = vector():set(0, 0, -1),   used = nil},
                {dir = vector():set(1, 0, -1),   used = nil}}
   self.npc = {}
   self.population = 0
   self.kamp_state = "idle"   
   -- Где то здесь распарсим патрульный путь и проапдейтим вектор позиций.
   -- 0 вершина - центр лагеря.
   -- 1 флаг - сектор занят, в поинте можно сидеть.
   -- 2 флаг - сектор занят, в поинте нельзя сидеть.
   for k = 1, self.patrol:count() - 1 do
      -- если есть 1 или 2 флажок - отметить сектор как занятый
      if self.patrol:flag(k,1) or
         self.patrol:flag(k,2)
      then
         -- отметить сектор как занятый
         for key,value in pairs(self.position) do
            dir = vector():sub(level.vertex_position(self.patrol:level_vertex_id(k)), level.vertex_position(self.center))
            if value.dir then
               yaw = yaw_degree(dir, value.dir)
               if yaw <=23 then
                  --'printf("KAMP node[%s], sector[%s,] yaw[%s]", k, key, yaw_degree(dir, value.dir))
                  value.used = -1
                  break                  
               end
            end
         end
         
      end
      
      -- если есть 1 флажок - создать место для сидения в точке пути
      if self.patrol:flag(k,1) then
         -- создать точку для сидения
         table.insert(self.position, {vertex = self.patrol:level_vertex_id(k)})
      end      
   end
   --print_table(self.position)
   --Таблица соответствий состояния лагеря и допустимых анимаций и звуков.   
   self.avail_state = {idle            = { directed   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  pre_harmonica      = { directed   = { "wait_harmonica"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  harmonica         = { directed   = { "play_harmonica"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  post_harmonica      = { directed   = { "wait_harmonica"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  pre_guitar         = { directed   = { "wait_guitar"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  guitar            = { directed   = { "play_guitar"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  post_guitar         = { directed   = { "wait_guitar"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  story            = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  post_story         = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  pre_joke         = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  joke            = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  post_joke         = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}}}
   self.avail_sound = {idle            = { directed = "idle"},
                  pre_harmonica      = { directed = "pre_harmonica", undirected = ""},
                  harmonica         = { directed = "play_harmonica", undirected = ""},
                  post_harmonica      = { directed = "", undirected = "reac_harmonica"},
                  pre_guitar         = { directed = "pre_guitar", undirected = ""},
                  guitar            = { directed = "play_guitar", undirected = ""},
                  post_guitar         = { directed = "", undirected = "reac_guitar"},
                  story            = { directed = "play_story", undirected = ""},
                  post_story         = { directed = "", undirected = "reac_story"},
                  pre_joke         = { directed = "pre_joke", undirected = ""},
                  joke            = { directed = "play_joke", undirected = ""},
                  post_joke         = { directed = "", undirected = "reac_joke"}}
   -- Таблица таймаутов по состоянию. Если состояние установилось, то некоторое время оно не может быт изменено.                  
   self.timeout    = {idle            = { min = 30000 },
                  pre_harmonica      = { min = 3000 },
                  harmonica         = { min = 5000, soundstart = true },
                  post_harmonica      = { min = 3000 },
                  pre_guitar         = { min = 3000 },
                  guitar            = { min = 5000, soundstart = true },
                  post_guitar         = { min = 3000 },
                  story            = { min = 1000, soundstart = true },
                  post_story         = { min = 3000 },
                  pre_joke         = { min = 3000 },
                  joke            = { min = 5000, soundstart = true },
                  post_joke         = { min = 3000 }}
   -- Таблица глобальных состояний лагеря.
   self.kamp_states = { idle = true,
                   pre_harmonica = false, harmonica = false, post_harmonica = false,
                   pre_guitar = false, guitar = false, post_guitar = false,
                   story = false, post_story = false,
                   pre_joke = true, joke = true, post_joke = true}
   -- Таблица допустимых переходов между состояниями с вероятностями.
   self.trans_kamp = { idle         = { idle = 0, pre_harmonica = 30, pre_guitar = 30, story = 0, pre_joke = 40 },
                  pre_harmonica   = { harmonica = 100 },
                  harmonica      = { post_harmonica = 100 },
                  post_harmonica   = { idle = 70, harmonica = 30 },
                  pre_guitar      = { guitar = 100 },
                  guitar         = { post_guitar = 100 },
                  post_guitar      = { idle = 70, guitar = 30 },
                  story         = { post_story = 100 },
                  post_story      = { idle = 100 },
                  pre_joke      = { joke = 100 },
                  joke         = { post_joke = 100 },
                  post_joke      = { idle = 100 }}
   -- Хранилище для режиссера лагеря. Режиссерем является сталкер, затеявший необычное поведение
   self.director = nil
end
function CKampManager:selectPosition(npc_id)
   -- создаем список доступных позиций
   --printf("KAMP. [%s] called select position", npc_id)
   local free = {}
   for k,v in pairs(self.position) do
      if v.used == nil then
         table.insert(free, k)
      end
   end
   --' затем из доступных позиций выбрать рандомно одну.
   if table.getn(free) > 0 then
      --printf("KAMP [%s] free node > 0", npc_id)
      local rr = math.random(table.getn(free))
      self.position[free[rr]].used = npc_id
      self.npc[npc_id].position = free[rr]
   end
   --printf("KAMP [%s] npc table", npc_id)
   --print_table(self.npc)
   --printf("KAMP [%s] position table", npc_id)
   --print_table(self.position)
end
function CKampManager:getDestVertex(npc_id, radius)
   --printf("get dest Vertex called [%s]", npc_id)
   if self.npc[npc_id].position == nil then
      --printf("-------debug_info-------------")
      --print_table(self.npc)
      --printf("-------debug_info-------------")
      --print_table(self.position)
      --printf("-------debug_info-------------")
      abort("get dest Vertex: nil [%s]", npc_id)
      return nil
   end
   
   local position = self.position[self.npc[npc_id].position]
   if position.vertex ~= nil then
      --printf("vertex preselected [%s]", npc_id)
      return position.vertex
   end
   -- высчитываем вертех по направлению
      local pp = level.vertex_in_direction(self.center, self.position[self.npc[npc_id].position].dir, radius)
      pp = level.vertex_in_direction(pp, vector():set(math.random(-1,1), 0, math.random(-1,1)), math.random(0,0.5))
   --printf("vertex selected [%s]", npc_id)      
   return pp      
end
function CKampManager:proceedState(npc)
   -- Проверка на таймаут
   local npc_id = npc:id()
   local active_sound_count = npc:active_sound_count()
   if self.npc[npc_id].need_sound_begin == true then
      if active_sound_count == 0 then
         return
      else         
         self.npc[npc_id].need_sound_begin = false
      end
   end
   if self.begin ~= nil and
      time_global() - self.begin < self.timeout[self.kamp_state].min
   then
      return
   end

   -- Если режиссер не закончил говорить - ждем конца фразы.
   if active_sound_count > 0 then
      return
   end

   --printf("Proceed state for [%s]", npc_id)
   -- В случае с историей переход обрабатывается отдельно
   if self.kamp_state == "post_story" then
      if self.story_last < self.story_max - 1 then
         self.npc[npc_id].begin = nil
         self.npc[npc_id].need_sound_begin = true
         self.director = npc_id
         self.kamp_state = "story"
         self.begin = time_global()
         for kk,vv in pairs(self.npc) do
            vv.new = true
         end      
         return
      else
         self.selected_story = nil
      end
   end
   -- Определяются допустимые в данный момент переходы.
   local temp = {}
   local max_rnd = 0
   for k,v in pairs(self.trans_kamp[self.kamp_state]) do      
      -- Определяются допустимые состояния для лагеря.
      if self.kamp_states[k] == true then
         temp[k] = v
         max_rnd = max_rnd + v
      end
   end
   -- Осуществляется рандомный взвешенный переход.
   if max_rnd == 0 then
      -- Если переходить некуда - переходим в айдл
      temp["idle"] = 100
      max_rnd = 100
   end
   local p = math.random(0,max_rnd)
   for k,v in pairs(temp) do
      p = p - v
      if p <= 0 then
         --printf("Selected [%s]", k)
         if k == "idle" then
            self.director = nil
            if self.kamp_state ~= "idle" then
               self.npc[npc_id].begin = nil
            end
         else
            self.npc[npc_id].begin = nil
            if self.timeout[k].soundstart == true then
               self.npc[npc_id].need_sound_begin = true
            end
            self.director = npc_id
            self.censor = nil
         end         
         self.kamp_state = k
         self.begin = time_global()
         -- Меняем таймаут для истории
         if k == "post_story" then
            local dep = sound_theme.theme[self.selected_story].depence[self.story_last]
            if dep and dep.min and dep.max then
               self.timeout["post_story"].min = math.random(dep.min, dep.max)*1000
            end
         end
         for kk,vv in pairs(self.npc) do
            vv.new = true
         end
         return
      end
   end
end
function CKampManager:proceedRole(npc, director)
   --printf("Proceed Role for [%s]", npc:id())
   -- Определить список доступных анимаций по состоянию лагеря.
   -- определить список доступных анимаций по наличию предметов
   -- выбрать одну из них (то же самое со звуком).
   local states = 0
   local sound = ""
   local state = ""
   local npc_id = npc:id()
   if self.npc[npc_id].begin == nil or
      time_global() - self.npc[npc_id].begin >= self.npc[npc_id].state_idle
   then
      if director then
         states = self.avail_state[self.kamp_state].directed
         sound = self.avail_sound[self.kamp_state].directed
      else
         states = self.avail_state[self.kamp_state].undirected
         sound = self.avail_sound[self.kamp_state].undirected
      end
      -- Выбирать новое состояние только раз в какое то время.
      local temp = {}
      for k,v in pairs(states) do
         if self.npc[npc_id].states[v] == true then
            table.insert(temp, v)
         end
      end
      
      -- Если мы решили говорить историю, надо выбрать какую именно говорить.
      if sound == "play_story" and self.selected_story == nil and db.story_by_id[npc_id] ~= nil then
         local story_num = table.getn(db.story_by_id[npc_id])
         if story_num > 0 then
            self.selected_story = db.story_by_id[npc_id][math.random(story_num)]
         end         
      end

      self.npc[npc_id].begin = time_global()
      state = temp[math.random(table.getn(temp))]
      self.npc[npc_id].state_selected = state
      self.npc[npc_id].state_idle = math.random(15000,20000)      
   else
      if director then
         sound = self.avail_sound[self.kamp_state].directed
      else
         sound = self.avail_sound[self.kamp_state].undirected
      end
      state = self.npc[npc_id].state_selected   
   end
   --printf("Proceed Role state [%s] sound [%s]", state, sound)   
   return state, sound
end
function CKampManager:updateNpc(npc)
   -- Проверка что сталкер может делать, а что нет.
   self:checkNpcAbility(npc)
   -- Просим лагерь выбрать текущее состояние. Менять состояние лагеря
   -- имеет право только режиссер.
   local npc_id = npc:id()
   local director = self.director == nil or self.director == npc_id
   if director   then
      self:proceedState(npc)
   end
   -- Говорим чудаку выбрать себе состояние для текущего состояния лагеря.
   local state, sound = self:proceedRole(npc, director)
   
   local substate = nil
   if state == "wait_harmonica" then
      if sound == "pre_harmonica" and self.npc[npc_id].new == true then
         xr_sound.set_sound_play(npc, "intro_music", math.random(2000,3000))
         self.npc[npc_id].new = false
      end
      state = "harmonica"
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "play_harmonica" then
      state = "harmonica"
      substate = 1
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "wait_guitar" then
      if sound == "pre_guitar" and self.npc[npc_id].new == true then
         xr_sound.set_sound_play(npc, "intro_music", math.random(2000,3000))
         self.npc[npc_id].new = false
      end
      state = "guitar"
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "play_guitar" then
      state = "guitar"
      substate = 1
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "declarate" then
      if self.npc[npc_id].new == true then
         if sound == "pre_joke" then
            xr_sound.set_sound_play(npc, "intro_joke", math.random(2000,3000))
         elseif sound == "play_joke" then
            xr_sound.set_sound_play(npc, "joke", math.random(2000,3000))
         elseif sound == "play_story" then
            xr_sound.set_sound_play(npc, self.selected_story)
            self.story_last, self.story_max = xr_sound.get_last_IDS(npc, self.selected_story)
         end
         self.npc[npc_id].new = false
      end

      if npc:character_community() == "monolith" then
         local t = math.mod(npc_id, 2)
         if t == 0 then
            state = "trans_0"
         else
            state = "trans_1"
         end
      elseif npc:character_community() == "zombied" then
         state = "trans_zombied"
      else
         local t = math.mod(npc_id, 3)
         if t == 0 then
            state = "sit"
         elseif t == 1 then
            state = "sit_ass"
         else
            state = "sit_knee"
         end
      end
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "trans" then
      if npc:character_community() == "monolith" then
         local t = math.mod(npc_id, 2)
         if t == 0 then
            state = "trans_0"
         else
            state = "trans_1"
         end
      elseif npc:character_community() == "zombied" then
         state = "trans_zombied"
      end
      xr_kamp.kamp_stalkers[npc_id] = false
   else
      xr_kamp.kamp_stalkers[npc_id] = true
   end
   -- Выбор реальных звуков
   if sound == "idle" then
      sound = "weather, state"
   elseif sound == "reac_guitar" then
      sound = "reac_music"
   elseif sound == "reac_harmonica" then
      sound = "reac_music"
   elseif sound == "reac_joke" then
      sound = ""   
      if self.npc[npc_id].new == true then
         if self.censor == nil then
            xr_sound.set_sound_play(npc, "reac_joke", math.random(2000,3000))
            self.censor = npc_id
         else
            xr_sound.set_sound_play(npc, "story_reac_laughter", math.random(100,300))
         end
         self.npc[npc_id].new = false
      end
   elseif sound == "reac_story" then
      sound = ""
      if self.npc[npc_id].new == true then
         local dep = sound_theme.theme[self.selected_story].depence[self.story_last+1]
         if dep then
            if dep.type == "all" then
               xr_sound.set_sound_play(npc, dep.theme, math.random(100,300))
            else
               sound = dep.theme
            end
         end
      end
   elseif sound == "reac_story" then
      sound = ""
   else
      sound = ""
   end

   --printf("Proceed Update Npc [%s] sound [%s]", state, sound)   
   return state, sound, substate
end
function CKampManager:checkNpcAbility(npc)
   local npc_id = npc:id()
   
   if npc:character_community() ~= "monolith" and
      npc:character_community() ~= "zombied"
   then
      -- есть колбасу
      if npc:object("kolbasa") then
         self.npc[npc_id].states["eat_kolbasa"] = true
      else
         self.npc[npc_id].states["eat_kolbasa"] = false
      end
      -- пить водку
      if npc:object("vodka") then
         self.npc[npc_id].states["eat_vodka"] = true
      else
         self.npc[npc_id].states["eat_vodka"] = false
      end
      -- пить енергитический напиток
      if npc:object("energy_drink") then
         self.npc[npc_id].states["eat_energy"] = true
      else
         self.npc[npc_id].states["eat_energy"] = false
      end
      -- есть хлеб
      if npc:object("bread") then
         self.npc[npc_id].states["eat_bread"] = true
      else
         self.npc[npc_id].states["eat_bread"] = false
      end
      -- играть на гармошке
--      if npc:object("harmonica_a") then
--         self.npc[npc_id].states["play_harmonica"] = true
--         self.npc[npc_id].states["wait_harmonica"] = true
--         self.kamp_states["pre_harmonica"] = true
--         self.kamp_states["harmonica"] = true
--         self.kamp_states["post_harmonica"] = true
--      else
         self.npc[npc_id].states["play_harmonica"] = false
         self.npc[npc_id].states["wait_harmonica"] = false
         self.kamp_states["pre_harmonica"] = false
         self.kamp_states["harmonica"] = false
         self.kamp_states["post_harmonica"] = false
--      end
      -- играть на гитаре
      if npc:object("guitar_a") then
         self.npc[npc_id].states["play_guitar"] = true
         self.npc[npc_id].states["wait_guitar"] = true
         self.kamp_states["pre_guitar"] = true
         self.kamp_states["guitar"] = true
         self.kamp_states["post_guitar"] = true
      else
         self.npc[npc_id].states["play_guitar"] = false
         self.npc[npc_id].states["wait_guitar"] = false
         self.kamp_states["pre_guitar"] = false
         self.kamp_states["guitar"] = false
         self.kamp_states["post_guitar"] = false
      end
      -- анекдоты
      if self.population > 1 then
         self.kamp_states["pre_joke"] = true
         self.kamp_states["joke"] = true
         self.kamp_states["post_joke"] = true
      else
         self.kamp_states["pre_joke"] = false
         self.kamp_states["joke"] = false
         self.kamp_states["post_joke"] = false
      end   
   end
   
   -- Если чувак знает истории, надо добавить их к лагерю
--[[
   if self.population > 1 and db.story_by_id[npc:id()] ~= nil then
      self.kamp_states["story"] = true
      self.kamp_states["post_story"] = true
   else
      self.kamp_states["story"] = false
      self.kamp_states["post_story"] = false   
   end
]]
end
function CKampManager:addNpc(npc)
   --printf("KAMP [%s] add npc", npc:name())
   if self.npc[npc:id()] ~= nil then
      --printf("NPC is already exist")
      return
   end
   
   if npc:character_community() == "monolith" or
      npc:character_community() == "zombied"
   then
      self.npc[npc:id()] = {name = npc:name(), position = nil, current = nil, speak = 0, states = {
                        stand_wait = false, sit = false, sit_ass = false, sit_knee = false, declarate = true,
                        eat_kolbasa = false, eat_vodka = false, eat_energy = false, eat_bread = false, trans = true,
                        play_harmonica = false, play_guitar = false, play_joke = false, play_story = false}}
   else
      self.npc[npc:id()] = {name = npc:name(), position = nil, current = nil, speak = 0, states = {
                        stand_wait = true, sit = true, sit_ass = true, sit_knee = true, declarate = true,
                        eat_kolbasa = false, eat_vodka = false, eat_energy = false, eat_bread = false, trans = false,
                        play_harmonica = false, play_guitar = false, play_joke = false, play_story = false}}
   end
   self:selectPosition(npc:id())   
end
function CKampManager:removeNpc(npc)
   --printf("KAMP [%s] remove npc", npc:name())
   local npc_id = npc:id()
   if self.npc[npc_id] ~= nil then
      -- Если удаляем режиссера - необходимо форсированно перевести лагерь в идловое состояние.
      if self.director == npc_id then
         self.director = nil
         self.npc[npc_id].begin = nil
         self.censor = nil
         self.kamp_state = "idle"
         self.begin = time_global()
         for kk,vv in pairs(self.npc) do
            vv.new = true
         end
         xr_sound.set_sound(npc, nil)
         stop_play_sound(npc)
      end
   
      self.position[self.npc[npc_id].position].used = nil
      self.npc[npc_id] = nil
   end
end

-->> Dynamic campfire mod
local camp_tbl = {
   ["esc2_st_fabric_kamp_1"] = {"zone_flame_small_0001", "lights_camp_fire_omni_r1_r2_0001"},
   ["esc_bridge_kamp_point"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0002"},
   ["esc_lager_camp_center"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0004"},
   ["esc_killers_kamp"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0004"},
   ["esc_blokpost_kamp"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["esc2_most_kamp_1"] = {"zone_flame_small_0006", "lights_camp_fire_omni_r1_r2_0006"},
   ["esc_assault_kamp_center1"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["esc_fabrika_bandit_camp_center"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["esc2_st_fabric_kamp_2"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["esc2_bandit_les_kamp_1"] = {"zone_flame_small_0008", "lights_camp_fire_omni_r1_r2_0008"},
   ["esc_stalker_camp_esc_fox_kamp"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["esc2_st_fox_place_kamp_1"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["esc_stalker_camp_camp_point"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},

   ["gar_angar_gar_seryi_kamp"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0003"},
   ["gar_smart_garage_kamp_1"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0003"},
   ["gar_smart_graveyard_kamp_1"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0004"},
   ["gar_bandit_agr_kamp_point1"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0004"},
   ["gar_bandit_agr_kamp_point"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0004"},
   ["gar_hellcar_group_kamp_point"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0004"},
   ["gar_smart_bandit_kamp_1"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0005"},
   ["gar_smart_stalkers_1_kamp_1"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0005"},
   ["gar_dolg_blokpost_kamp_point"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0006"},
   
   ["val_smart_bandit_2_kamp_2"] = {"zone_flame_small_0006", "lights_camp_fire_omni_r1_r2_0006"},
   ["val_smart_bandit_2_kamp_1"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["val_lager_bandits_kamp2"] = {"zone_flame_small_0010", "lights_camp_fire_omni_r1_r2_0010"},
   ["val_lager_bandits_kamp3"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["val_lager_bandits_kamp1"] = {"zone_flame_small_0012", "lights_camp_fire_omni_r1_r2_0012"},
   ["val_smart_bandit_1_kamp_1"] = {"zone_flame_small_0015", "lights_camp_fire_omni_r1_r2_0015"},
   ["val_rob_kamp"] = {"zone_flame_small_0015", "lights_camp_fire_omni_r1_r2_0015"},
   ["val_exit1_ambush_kamp_1"] = {"zone_flame_small_0017", "lights_camp_fire_omni_r1_r2_0017"},
   ["val_smart_bandit_3_kamp_1"] = {"zone_flame_small_0017", "lights_camp_fire_omni_r1_r2_0017"},
   
   ["bar_visitors_kamp_1"] = {"zone_flame_small_0000", "lights_camp_fire_omni_r1_r2_0000"},
   ["bar_visitors_kamp_2"] = {"zone_flame_small_0001", "lights_camp_fire_omni_r1_r2_0001"},
   ["bar_visitors_kamp_3"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["bar_dolg_general_kamp_center"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0003"},
   ["bar_visitors_kamp_4"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0004"},
   
   ["ros_smart_stalker_bandits1_kamp_1"] = {"zone_flame_small_0000", "lights_camp_fire_omni_r1_r2_0000"},
   
   ["yan_st_stalker2_kamp_1"] = {"zone_flame_small_0008", "lights_camp_fire_omni_r1_r2_0008"},
   
   ["mil_monolit_kamp1"] = {"zone_flame_small_0000", "lights_camp_fire_omni_r1_r2_0000"},
   ["mil_fneutral_kamp"] = {"zone_flame_small_0000", "lights_camp_fire_omni_r1_r2_0000"},
   ["mil_monolit_kamp2"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0002"},
   ["mil_khutor_kamp_center"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0003"},
   ["mil_smart_dolg_kamp_kamp_1"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["mil_dolg_camp_center"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["mil_village_kamp"] = {"zone_flame_small_0006", "lights_camp_fire_omni_r1_r2_0006"},
   ["mil_fblockpost_kamp"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["mil_monolit_kamp3"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["mil_lager_kamp_1"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["mil_mercs_kamp_1"] = {"zone_flame_small_0010", "lights_camp_fire_omni_r1_r2_0010"},
   ["mil_bandit_kamp_1"] = {"zone_flame_small_0011", "lights_camp_fire_omni_r1_r2_0011"},
   ["mil_freedom_camp_center1"] = {"zone_flame_small_0012", "lights_camp_fire_omni_r1_r2_0012"},
   
   ["rad_prip_teleport_kamp_center"] = {"zone_flame_small_0001", "lights_camp_fire_omni_r1_r2_0001"},
   ["rad2_prip_teleport_kamp_1"] = {"zone_flame_small_0001", "lights_camp_fire_omni_r1_r2_0001"},
   ["rad_valley_kamp"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0002"},
   ["rad_entrance_kamp"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["rad2_prip_teleport_kamp_2"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["rad_mil_entrance_kamp_center"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["rad_prip_road_kamp_center"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["rad_freedom_vs_duty_kamp_center1"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["rad_freedom_vs_duty_kamp_center"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["rad2_loner_0001_kamp_1"] = {"zone_flame_small_0008", "lights_camp_fire_omni_r1_r2_0008"},
   ["rad2_loner_0002_kamp_1"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["rad_antenna_monolith_kamp"] = {"zone_flame_small_0010", "lights_camp_fire_omni_r1_r2_0010"},
   ["rad_antenna_patrol_kamp"] = {"zone_flame_small_0010", "lights_camp_fire_omni_r1_r2_0010"},
   ["rad2_loner_0000_kamp_1"] = {"zone_flame_small_0013", "lights_camp_fire_omni_r1_r2_0013"},
   
   ["pri_smart_monolith_stalker5_kamp_1"] = {"zone_flame_small_0018", "lights_camp_fire_omni_r1_r2_0005"},
   ["pri_smart_dolg_stalker1_kamp_1"] = {"zone_flame_small_0021", "lights_camp_fire_omni_r1_r2_0008"},
   ["pri_wave7_kamp_1"] = {"pri_zone_flame_small_0003", "pri_r1_r2_0001"},
   ["pri_sideway_left_kamp"] = {"pri_zone_flame_small_0043", "pri_r1_r2_00002"},
   ["pri_smart_freedom_stalker1_kamp_1"] = {"pri_zone_flame_small_0043", "pri_r1_r2_0002"},
   ["pri_smart_monolith_stalker4_kamp_1"] = {"pri_zone_flame_small_0044", "pri_r1_r2_0003"},
   ["pri_monolith_kamp2"] = {"pri_zone_flame_small_0026", "pri_r1_r2_0004"},
   ["pri_monolith_kamp3"] = {"pri_zone_flame_small_0021", "pri_r1_r2_0005"},
   ["pri_monolith_kamp5"] = {"pri_zone_flame_small_0045", "pri_r1_r2_0006"},
   ["pri_monolith_kamp7"] = {"pri_zone_flame_small_0000", "pri_r1_r2_0007"},
   ["pri_smart_monolith_stalker6_kamp_1"] = {"pri_zone_flame_small_0035", "pri_r1_r2_0008"}
}

   lvl_objs = {}
   local kamps_info = {}

function CKampManager:increasePops(npc)
   self.population = self.population + 1
   local camp_name = camp_tbl[self.kamp_name]
   if self.population == 1 and camp_name then
      local flame = camp_name[1]
      local light = camp_name[2]
      
--      kamps_info[self.kamp_name] = nil
--      if not kamps_info[self.kamp_name] then
         kamps_info[self.kamp_name] = {}
         kamps_info[self.kamp_name].time = time_global()
         kamps_info[self.kamp_name].prtcl = nil
         kamps_info[self.kamp_name].state = nil
--      end
      
      for i,o in pairs(lvl_objs) do
         local obj = o
         if obj and obj:name() == flame then
            kamps_info[self.kamp_name].obj_fire = obj
            obj:enable_anomaly()
         end
         if obj and obj:name() == light then
            kamps_info[self.kamp_name].obj_light = obj
         end
      end
   end
end

function CKampManager:decreasePops(npc)
   self.population = self.population - 1
   local camp_name = camp_tbl[self.kamp_name]
   if self.population < 1 and camp_name then
      local flame = camp_name[1]
      local light = camp_name[2]
      
--      if not kamps_info[self.kamp_name] then
         kamps_info[self.kamp_name] = {}
         kamps_info[self.kamp_name].time = time_global()
         kamps_info[self.kamp_name].prtcl = particles_object("dyn_kfire\\dyingfire")
         kamps_info[self.kamp_name].state = nil
--      end
      
      for i,o in pairs(lvl_objs) do
         local obj = o
         if obj and obj:name() == flame then
            kamps_info[self.kamp_name].obj_fire = obj
         end
         if obj and obj:name() == light then
            kamps_info[self.kamp_name].obj_light = obj
         end
      end
   end
end

function update(time)
   for i,v in pairs(kamps_info) do
      local kamp_name = i
      local kamp_fire = v.obj_fire
      local kamp_light = v.obj_light
      local kamp_time = v.time
      local kamp_prtcl = v.prtcl
      local kamp_state = v.state
      
      if kamp_fire and kamp_light then
         if kamp_prtcl == nil and kamp_time + 5000 < time then
            kamp_light:get_hanging_lamp():turn_on()
            kamps_info[kamp_name] = nil
         end
         
         if kamp_prtcl then
            if kamp_state == nil and kamp_time + 10000 < time then
               kamps_info[kamp_name].state = 1
               kamp_prtcl:play_at_pos(kamp_fire:position())
            end
            
            if kamp_time + 15000 < time then
               kamp_fire:disable_anomaly()
            end
            
            if kamp_time + 48000 < time then
               kamp_light:get_hanging_lamp():turn_off()
            end
            
            if kamp_time + 120000 < time then
               kamp_prtcl:stop()
               kamps_info[kamp_name] = nil
            end
         end
      end
   end
end
--<< Dynamic campfire mod
----------------------------------------------------------------------------------------------------------------------
--Kamp binder
----------------------------------------------------------------------------------------------------------------------
function add_to_binder(object, ini, scheme, section, storage)
   local operators      = {}
   local properties   = {}

   local manager = object:motivation_action_manager()
   
   properties["kamp_end"]      = xr_evaluators_id.stohe_kamp_base + 1
   properties["on_position"]   = xr_evaluators_id.stohe_kamp_base + 2
   properties["contact"]      = xr_evaluators_id.stohe_meet_base + 1   

   operators["go_position"]   = xr_actions_id.stohe_kamp_base + 1
   operators["wait"]      = xr_actions_id.stohe_kamp_base + 3

   -- Evaluators                                                                           
   manager:add_evaluator (properties["kamp_end"],       this.evaluator_kamp_end      ("kamp_end", storage, "kamp_end"))
   manager:add_evaluator (properties["on_position"],   this.evaluator_on_position   ("kamp_on_position", storage, "kamp_on_position"))

   --printf("PRP %s", stalker_ids.property_script)

   -- Actions
   local action = this.action_wait (object:name(),"action_kamp_wait", storage)
   action:add_precondition      (world_property(stalker_ids.property_alive, true))
   action:add_precondition      (world_property(stalker_ids.property_danger,false))
   action:add_precondition      (world_property(stalker_ids.property_enemy,   false))
   action:add_precondition      (world_property(stalker_ids.property_anomaly,false))
   xr_motivator.addCommonPrecondition(action)
   action:add_precondition      (world_property(properties["on_position"],    true))
   action:add_effect       (world_property(properties["kamp_end"],    true))
   manager:add_action (operators["wait"], action)
   xr_logic.subscribe_action_for_events(object, storage, action)
   
   action = this.action_go_position (object:name(),"action_go_kamp", storage)
   action:add_precondition      (world_property(stalker_ids.property_alive, true))
   action:add_precondition      (world_property(stalker_ids.property_danger,false))
   action:add_precondition      (world_property(stalker_ids.property_enemy,   false))
   action:add_precondition      (world_property(stalker_ids.property_anomaly,false))
   xr_motivator.addCommonPrecondition(action)
   action:add_precondition    (world_property(properties["on_position"],    false))
   action:add_effect       (world_property(properties["on_position"],    true))
   manager:add_action (operators["go_position"], action)

   action = manager:action (xr_actions_id.alife)   
   action:add_precondition      (world_property(properties["kamp_end"],      true))

end
-- включение лагеря
function set_scheme(npc, ini, scheme, section, gulag_name)
   local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)

   st.logic     = xr_logic.cfg_get_switch_conditions(ini, section, npc)      
   
   st.center_point = utils.cfg_get_string(ini, section, "center_point", npc, true,  gulag_name)
   st.radius      = utils.cfg_get_number(ini, section, "radius", npc, false, 2)
   
   if kamps[st.center_point] == nil then
      kamps[st.center_point] = CKampManager(st.center_point)
   end
   kamps[st.center_point]:addNpc(npc)
   st.pos_vertex = nil

   st.def_state_moving = utils.cfg_get_string(ini, section, "def_state_moving", npc, false, "", "walk")
end


dodam jeszcze że nie wgrywałem folderu textures (nie widziałem potrzeby) i pliku particles.xr tylko zamieniłem 'particles_object("dyn_kfire\\dyingfire")' na 'particles_object("explosions\\explosion_01")'

a tutaj niektóre ścinki ze skryptu co wykonywałem ..
Kod: Zaznacz wszystko
lvl_objs = {}
local kamps_info = {}
local name_anom = ""

function con(msg)
get_console():execute(msg)
end

function is_anomaly_near_actor(name_anom,anomy,distance)
   local iana = false
   if anomy:position():distance_to(db.actor:position()) < distance then
      iana = true
   end
   --[[
   if name_anom == "mil_lager_kamp_1" then
      iana = true
   end
   ]]
   return iana
end

function set_enable_anom(a,b,c,d)
   kamps_info[a].timez = c + d
end

local timex = time_global()

set_enable_anom(self.kamp_name,obj,timex,5000)


      if kamp_timez ~= nil then
         if kamp_timez > time and kamp_timez_restart > time then
            kamps_info[kamp_name].timez = nil
            kamps_info[kamp_name].timez_restart = time + 10000
            kamp_fire:enable_anomaly()
         end
      end
--[[
      local kamp_restart = v.restart
      local kamp_res_tim = v.restart_timer
      local kamp_fired = v.fired or false
      if is_anomaly_near_actor(i,kamp_fire,125) and not kamp_fired then
            if i == "mil_lager_kamp_1" then
               con("disable_an_anomaly")
               con(i)
            end
         kamp_fire:disable_anomaly()
         kamps_info[kamp_name].fired = true
         kamps_info[kamp_name].restart = true
         kamps_info[kamp_name].restart_timer = time + 5000
      end
      if kamp_restart then
         if kamp_res_tim < time then
            if i == "mil_lager_kamp_1" then
               con("enable_an_anomaly")
               con(i)
            end
            kamps_info[kamp_name].restart = nil
            kamps_info[kamp_name].restart_timer = 0
            kamp_fire:enable_anomaly()
         end
      end
      if not is_anomaly_near_actor(i,kamp_fire,50) then
         kamps_info[kamp_name].fired = false
      end

może jeszce komuś cos z tego uda się wykrzesać :C
prosżę pomagicie :C
Awatar użytkownika
max1071
Stalker

Posty: 135
Dołączenie: 04 Gru 2010, 13:07
Ostatnio był: 09 Cze 2023, 20:21
Frakcja: Wolność
Ulubiona broń: TRs 301
Kozaki: 23

Re: Obrażenia zadawane przez ogniska

Postprzez Wheeljack w 06 Gru 2016, 10:00

Jeżeli zależy Ci na przeżyciu Wilka to do czasu aż wyjdzie z ogniska możesz zwiększyć odporność npc na obrażenia zadawane przez ogień. Tylko nie pamiętam gdzie to jest, może w actor.ltx? Nawet nie mam przed sobą gamedaty żeby znaleźć.
I na drugi raz dla kodu użyj [code] zamiast spojlera, poprawiłem.
Awatar użytkownika
Wheeljack
Administrator

Posty: 1918
Dołączenie: 13 Kwi 2009, 18:52
Ostatnio był: 13 Wrz 2023, 13:49
Miejscowość: Fraktal
Ulubiona broń: GP 37
Kozaki: 722

Re: Obrażenia zadawane przez ogniska

Postprzez Pangia w 06 Gru 2016, 10:45

Wheeljack napisał(a):Tylko nie pamiętam gdzie to jest, może w actor.ltx? Nawet nie mam przed sobą gamedaty żeby znaleźć.

Jak sama nazwa wskazuje, actor.ltx jest plikiem definiującym cechy gracza, a nie jakiegokolwiek NPC :u3: Jeśli już to, m_stalker.ltx, o ile ma on wpływ na specjalnych NPC.
Proszę państwa, sto pięćdziesiąt kilometrów na godzinę w ciągu kilku sekund, wspaniały wynik. Gdyby w ten sposób można było wypie*dolić z polskiej polityki tych wszystkich śmieci z Okrągłego Stołu, Leszka Millera, byłoby… cudownie i każdemu bym ku*wa kupił po takim Ferrari, byleby w piz*u pojechali tym PROSTO do swojego ukochanego… Izraela. SYJONIŚCI Europy, jedźcie do siebie! Pozdrawiam, Zbigniew Stonoga. Nie jestem antysemitą!
Awatar użytkownika
Pangia
Monolit

Posty: 4280
Dołączenie: 27 Maj 2012, 10:49
Ostatnio był: 28 Lis 2017, 19:49
Miejscowość: Kukle Karakańskie
Ulubiona broń: TOZ34
Kozaki: 854

Re: Obrażenia zadawane przez ogniska

Postprzez Alchemik w 06 Gru 2016, 16:03

Chłopcy a nie lepiej powiedzieć mu jak zmienić trasę przejścia Wilka? :P Zwiększenie wytrzymałości Wilka nic nie da bo i tak czasem utknie na dobre w ognisku i prędzej czy później go sfajczy.
Alchemik
Weteran

Posty: 656
Dołączenie: 17 Lut 2010, 12:59
Ostatnio był: 09 Sie 2017, 22:09
Ulubiona broń: --
Kozaki: 207

Re: Obrażenia zadawane przez ogniska

Postprzez PMG w 07 Gru 2016, 18:01

W zone_kampfire.ltx znajduje się sekcja "zone_flame_small". Odszukaj ją, a potem linijki "min_start_power" i "max_start_power". Następnie wyzeruj je tzn. ustaw wartości na 0.00. Powinno zadziałać.

@Alchemik, zmiana trasy wymaga grzebania w spawnie, co jest jeszcze trudniejsze niż zmiana configu.

Za ten post PMG otrzymał następujące punkty reputacji:
Positive Wheeljack.
Awatar użytkownika
PMG
Redaktor

Posty: 376
Dołączenie: 12 Gru 2010, 10:30
Ostatnio był: 06 Gru 2023, 13:29
Frakcja: Zombie
Ulubiona broń: Viper 5 9x18
Kozaki: 127

Re: Obrażenia zadawane przez ogniska

Postprzez max1071 w 08 Gru 2016, 00:49

Dzięki stalkiery :D

zrobiłem małe coś ale niestety czasem krzaczy się nie wiem z jakiego powodu ale musi być dość poważny bo nawet loga nie zapisuje

otóż zrobiłem znowu ten timeout na 5 sekund po zrespieniu się danej postaci koło ogniska (ognisko wyłączone) po 5 sekundach ognisko się zapala. ( set_enable_anom(self.kamp_name,obj,timex,5000))

to odpowiada za włączenie po tych pięcu sekundach:
if kamp_timez ~= nil then
if kamp_timez > time and not kamp_aon then
kamps_info[kamp_name].timez = nil
kamps_info[kamp_name].aenabled = true
kamp_fire:enable_anomaly()
end
end

po ilości (self.population < 1) wyłącza ognisko (obj.disable_anomaly())
obj:disable_anomaly()
kamps_info[self.kamp_name].aenabled = false

daję skrypty tutaj ponieważ działa a krzaczy .. jak to wheeljack powiedział w code nie w spojla
bind_stalker.script:
Kod: Zaznacz wszystko
function con(msg)
get_console():execute(msg)
end

function init    (obj)
   xr_motivator.AddToMotivator(obj)
end

function actor_init    (npc)
   npc:bind_object(actor_binder(npc))
end

local game_difficulty_by_num = {
   [0] = "gd_novice",
   [1] = "gd_stalker",
   [2] = "gd_veteran",
   [3] = "gd_master"
   }

lasthealth  = 0
lasttime   = 0
post_process = 0
local weapon_hide = false
-->> Dynamic campfire mod
local scan_flag
local upd_time
--<< Dynamic campfire mod
----------------------------------------------------------------------------------------------------------------------
class "actor_binder" (object_binder)
----------------------------------------------------------------------------------------------------------------------
function actor_binder:__init (obj) super(obj)
   self.bCheckStart = false
   self.weather_manager = level_weathers.WeatherManager()
   self.actor_detector = xr_detector.actor_detector()
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:net_spawn(data)
   printf("actor net spawn")      

   level.show_indicators()

   self.bCheckStart = true
   self.weapon_hide = false -- спрятано или нет оружие при разговоре.
   weapon_hide = false -- устанавливаем глобальный дефолтовый флаг.

   if object_binder.net_spawn(self,data) == false then
      return false
   end

   db.add_actor(self.object)
   
   if self.st.disable_input_time == nil then
      level.enable_input()
   end

   self.weather_manager:reset()
--   game_stats.initialize ()

   if(actor_stats.add_to_ranking~=nil)then
      actor_stats.add_to_ranking(self.object:id())
   end

   --' Загружаем настройки дропа
   death_manager.init_drop_settings()

   return true
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:net_destroy()
   if(actor_stats.remove_from_ranking~=nil)then
      actor_stats.remove_from_ranking(self.object:id())
   end
--   game_stats.shutdown ()
   db.del_actor(self.object)

    sr_light.clean_up ()

   self.object:set_callback(callback.inventory_info, nil)
   self.object:set_callback(callback.article_info, nil)
   self.object:set_callback(callback.on_item_take, nil)
   self.object:set_callback(callback.on_item_drop, nil)
   --self.object:set_callback(callback.actor_sleep, nil)
   self.object:set_callback(callback.task_state, nil)
   self.object:set_callback(callback.level_border_enter, nil)
   self.object:set_callback(callback.level_border_exit, nil)
   self.object:set_callback(callback.take_item_from_box, nil)

   if sr_psy_antenna.psy_antenna then
      sr_psy_antenna.psy_antenna:destroy()
      sr_psy_antenna.psy_antenna = false
   end

   xr_sound.stop_all_sound_object()

   object_binder.net_destroy(self)
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:reinit()
   object_binder.reinit(self)
   
   local npc_id = self.object:id()

   db.storage[npc_id] = { }

   self.st = db.storage[npc_id]
   self.st.pstor = nil

   self.next_restrictors_update_time = -10000

   self.object:set_callback(callback.inventory_info, self.info_callback, self)
   self.object:set_callback(callback.article_info, self.article_callback, self)
   self.object:set_callback(callback.on_item_take, self.on_item_take, self)
   self.object:set_callback(callback.on_item_drop, self.on_item_drop, self)
   self.object:set_callback(callback.trade_sell_buy_item, self.on_trade, self) -- for game stats
   --self.object:set_callback(callback.actor_sleep, self.sleep_callback, self)
   self.object:set_callback(callback.task_state, self.task_callback, self)
   --self.object:set_callback(callback.map_location_added, self.map_location_added_callback, self)
   self.object:set_callback(callback.level_border_enter, self.level_border_enter, self)
   self.object:set_callback(callback.level_border_exit, self.level_border_exit, self)
   self.object:set_callback(callback.take_item_from_box, self.take_item_from_box, self)
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:take_item_from_box(box, item)
   local story_id = box:story_id()
   if story_id == nil then
      return
   end

   treasure_manager.take_item_from_box(box, story_id)
--[[   
   local respawner = se_respawn.get_respawner_by_parent(story_id)
   if respawner == nil then
      return
   end
   
   --' Необходимо уменьшить счетчик в респавнере
   respawner:remove_spawned(item:id())

   local smart_terrain = db.strn_by_respawn[respawner:name()]
   if smart_terrain == nil then
      return
   end

   local npc = smart_terrain.gulag:get_nearest_online_obj(db.actor:position())
    if npc ~= nil then
       xr_sound.set_sound_play(npc, "reac_box")
       xr_gulag.setGulagEnemy(smart_terrain:name() , db.actor)      
    end
]]
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:level_border_enter(npc, info_id)
   self.actor_detector:actor_enter()
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:level_border_exit(npc, info_id)
   self.actor_detector:actor_exit()
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:info_callback(npc, info_id)
   printf("*INFO*: npc='%s' id='%s'", npc:name(), info_id)
   --' Сюжет
   level_tasks.proceed(self.object)
   -- Отметки на карте
   level_tasks.process_info_portion(info_id)
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:on_trade (item, sell_bye, money)
    if sell_bye == true then
       game_stats.money_trade_update (money)
    else       
       game_stats.money_trade_update (-money)
    end   
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:article_callback(npc, group, name)
   --printf("article_callback [%s][%s]", group, name)
   if device().precache_frame >1 then return end
   
   if group == "Diary" then
      news_manager.send_encyclopedy("diary", group)
   else
      news_manager.send_encyclopedy("encyclopedy", group)
   end
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:on_item_take (obj)
    level_tasks.proceed(self.object)
    --game_stats.update_take_item (obj, self.object)
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:on_item_drop (obj)
    level_tasks.proceed(self.object)
   -- NGC REPAIR MOD START
   ngc_mod.itemuse(obj)
   -- NGC REPAIR MOD END
   use_mod_a.itemuse_mod(obj)
   remove_item.remove_mod(obj)
    --game_stats.update_drop_item (obj, self.object)
end
----------------------------------------------------------------------------------------------------------------------

function actor_binder:task_callback(_task, _objective, _state)
   task_manager.task_callback(_task:get_id(), _objective:get_idx(), _state)
   if _objective:get_idx() == 0 then
      if _state == task.fail then
         news_manager.send_task(db.actor, "fail", _task, _objective)
      elseif _state == task.completed then
         task_manager.reward_by_task(_task)
         news_manager.send_task(db.actor, "complete", _task, _objective)
      else
         news_manager.send_task(db.actor, "new", _task, _objective)
      end
   else
      if _task:get_objective(0):get_state() == task.in_progress then
         news_manager.send_task(db.actor, "update", _task, _objective)
      end
   end
end

----------------------------------------------------------------------------------------------------------------------
function actor_binder:map_location_added_callback(spot_type_str, object_id)
   if (false==app_ready()) or (device().precache_frame>1) then return end
   --'news_manager.send_task(db.actor, "new")
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:update(delta)
   object_binder.update(self, delta)

   -- DEBUG slowdown
--   slowdown.update()

   local time = time_global()
   
   game_stats.update (delta, self.object)

   -- апдейт погоды
   self.weather_manager:update()
   
   -- апдейт схемы детектора
   self.actor_detector:update()

   -- апдейт звуковой схемы актера
   xr_sound.update_actor()
   
   --' Проверка потери жизни
--[[
   if self.object.health - lasthealth > 0.001 or
      self.object.health - lasthealth < -0.001 then
      printf("%f | %f", self.object.health, self.object.health - lasthealth, game.time() - lasttime)
      lasthealth = self.object.health
      lasttime = game.time()
   end
]]   
   -- Обновление отключения ввода с клавиатуры.
   if self.st.disable_input_time ~= nil and
      game.get_game_time():diffSec(self.st.disable_input_time) >= self.st.disable_input_idle
   then
      level.enable_input()
      self.st.disable_input_time = nil
   end
   -- Обновление сна с переносом чувака в указанную позицию
   if self.st.sleep_relocate_time ~= nil and
      game.get_game_time():diffSec(self.st.sleep_relocate_time) >= self.st.sleep_relocate_idle
   then
      self.object:set_actor_position(self.st.sleep_relocate_point)
      local dir = self.st.sleep_relocate_point:sub(self.st.sleep_relocate_look)
      self.object:set_actor_direction(dir:getH())
      self.st.sleep_relocate_time = nil
   end

   -- Апдейт прятание оружия игрока во время диалога
   if weapon_hide == true or self.object:is_talking() then
      if self.weapon_hide == false then
         self.object:hide_weapon()
         self.weapon_hide = true
      end
   else
      if self.weapon_hide == true then
         self.object:restore_weapon()
         self.weapon_hide = false
      end
   end   

   -- обновление рестрикторов, которые под логикой, срабатывает через интервалы времени
   if self.next_restrictors_update_time < time then
      bind_restrictor.actor_update(delta)

      self.next_restrictors_update_time = time + 200

      task_manager.actor_update()
   end

   -- обновление постпроцессов
   if post_process ~= 0 then
      if post_process:update () == true then
         post_process = 0
      end
   end

   -- обновление пси-антенны
   if sr_psy_antenna.psy_antenna then
      sr_psy_antenna.psy_antenna:update(delta)
   end

   --' Вывод сообщения о большой радиации
   if self.object.radiation >= 0.7 then
      local hud = get_hud()
      local custom_static = hud:GetCustomStatic("cs_radiation_danger")
      if custom_static == nil then
         hud:AddCustomStatic("cs_radiation_danger", true)
         hud:GetCustomStatic("cs_radiation_danger"):wnd():SetTextST("st_radiation_danger")
      end
   else
      local hud = get_hud()
      local custom_static = hud:GetCustomStatic("cs_radiation_danger")
      if custom_static ~= nil then
         hud:RemoveCustomStatic("cs_radiation_danger")
      end
   end



    if self.bCheckStart then
      printf("SET DEFAULT INFOS")      

      if not has_alife_info("storyline_actor_start") and
         (level.name() == "l01_escape")
      then
         self.object:give_info_portion("storyline_actor_start")
         _G.g_start_avi = true
         printf("*AVI* RUN START AVI")         
      end

--      if not has_alife_info("encyclopedy") then
--         self.object:give_info_portion("encyclopedy")
--      end

      if not has_alife_info("global_dialogs") then
         self.object:give_info_portion("global_dialogs")
      end

      if not has_alife_info("level_changer_icons") then
         self.object:give_info_portion("level_changer_icons")
      end

      level_tasks.add_lchanger_location()

      self.bCheckStart = false      
   end
   if save_time == nil then
      save_time = time + 30000
   elseif save_time < time then
      save_time = time + 30000
      save_manager.autosave()
   end
   -->> Dynamic campfire mod
   if scan_flag == nil then
      scan_flag = 1
      local lvl = level.name()
      local exc_tbl = {
         ["zone_flame_small_0002"] = {"l05_bar"},
         ["zone_flame_small_0005"] = {"l06_rostok"},
         ["zone_flame_small_0006"] = {"l06_rostok"},
         ["zone_flame_small_0007"] = {"l06_rostok"},
         ["zone_flame_small_0008"] = {"l06_rostok"},
         ["zone_flame_small_0010"] = {"l06_rostok"},
         ["zone_flame_small_0012"] = {"l11_pripyat"},
         ["zone_flame_small_0013"] = {"l11_pripyat"},
         ["zone_flame_small_0024"] = {"l11_pripyat"},
         ["zone_flame_small_0025"] = {"l11_pripyat"},
         ["lights_camp_fire_omni_r1_r2_0002"] = {"l05_bar"},
         ["lights_camp_fire_omni_r1_r2_0011"] = {"l11_pripyat"},
         ["lights_camp_fire_omni_r1_r2_0012"] = {"l11_pripyat"},
         ["lights_camp_fire_omni_r1_r2_0031"] = {"l08_yantar"}
--         МОЖЕТ БЫТЬ ТАК:   ["zone_flame_small_9999"] = {"l01_escapel02_garbagel05_barl07_military"},
--         МОЖЕТ БЫТЬ ТАК:   ["lights_camp_fire_omni_r1_r2_9999"] = {"l01_escapel02_garbagel05_barl07_military"}
      }
      for id=1, 65535 do
         local obj = level.object_by_id(id)
         if obj then
            local name = obj:name()
            local exc_obj = exc_tbl[name]
            if exc_obj and string.find(exc_obj[1], lvl) then
--               printf("EXEPTIONS: OBJ:[%s] LEVELS:[%s]", name, exc_obj[1])
            else
               if obj:section() == "zone_flame_small" then
                  table.insert(xr_kamp.lvl_objs, obj)
                  obj:disable_anomaly()
               elseif string.find(name, "r1_r2") then
                  table.insert(xr_kamp.lvl_objs, obj)
                  obj:get_hanging_lamp():turn_off()
               -- Масляные горелки (требуется доп. правка particles.xr)
--               elseif string.find(name, "light_gas") then
--                  obj:get_hanging_lamp():turn_off()
               end
            end
         end
      end
   end
   if upd_time == nil then
      upd_time = time + 500
   elseif upd_time < time then
      upd_time = time + 500
      --con("DCM-upd_time")
      xr_kamp.update(time)
   end
   --<< Dynamic campfire mod
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:save(packet)
   
   local save_treasure_manager = true
   
   printf("actor_binder:save(): self.object:name()='%s'", self.object:name())
   object_binder.save(self, packet)

   --' Сохраняем уровень сложности
   if save_treasure_manager == true then
      packet:w_u8(level.get_game_difficulty() + 128)
   else
      packet:w_u8(level.get_game_difficulty())
   end


   --' Сохраняем данные об отключенном вводе
   if self.st.disable_input_time == nil then
      packet:w_bool(false)
   else
      packer:w_bool(true)
      utils.w_CTime(packet, self.st.disable_input_time)
   end

   xr_logic.pstor_save_all(self.object, packet)
   self.weather_manager:save(packet)

   sr_psy_antenna.save( packet )
   
   if save_treasure_manager == true then
      treasure_manager.save(packet)     
   end                                 

   task_manager.save(packet)
   self.actor_detector:save(packet)   
end
----------------------------------------------------------------------------------------------------------------------
function actor_binder:load(reader)
   printf("actor_binder:load(): self.object:name()='%s'", self.object:name())
   object_binder.load(self, reader)
   printf("actor_binder:object_binder.load(): self.object:name()='%s'", self.object:name())

   --' Загружаем уровень сложности
   local game_difficulty = reader:r_u8()
   
   local load_treasure_manager = false     
   if game_difficulty >= 128 then           
      game_difficulty = game_difficulty - 128
      load_treasure_manager = true           
   end                                     

   
   get_console():execute("g_game_difficulty "..game_difficulty_by_num[game_difficulty])

   if reader:r_eof() then
      abort("SAVE FILE IS CORRUPT")
   end

   local stored_input_time = reader:r_u8()
   if stored_input_time == true then
      self.st.disable_input_time = utils.r_CTime(reader)
   end

   xr_logic.pstor_load_all(self.object, reader)
   self.weather_manager:load(reader)

   sr_psy_antenna.load(reader)
   
   if load_treasure_manager == true then
      treasure_manager.load(reader)     
   end                                 

   
   task_manager.load(reader)
   self.actor_detector:load(reader)   
end
----------------------------------------------------------------------------------------------------------------------

--старт префетча звуков
--if string.find(command_line(), "-noprefetch") == nil then
--   sound_prefetch.prefetch_sounds()
--end


-- Weapon functions
function hide_weapon()
   weapon_hide = true
end
function restore_weapon()
   weapon_hide = false
end

// this is test for section iteration
/**
local function test_section_iteration(file_name, section_name)
   printf         ("file    : %s",file_name)
   printf         ("section : %s",section_name)
   
   local         file = ini_file(file_name)
   local         n = file:line_count(section_name)
   printf         ("lines   : %d",n)
   
   local         id, value = "", "", result
   for i=0,n-1 do
      result, id, value   = file:r_line(section_name,i,"","")
      printf      ("line %d : %s = %s",i,id,value)
   end
end

test_section_iteration("system.ltx","space_restrictor")
/**/





xr_kamp.script:
Kod: Zaznacz wszystko
lvl_objs = {}
local kamps_info = {}
local name_anom = ""

function con(msg)
get_console():execute(msg)
end

function is_anomaly_near_actor(name_anom,anomy,distance)
   local iana = false
   if anomy:position():distance_to(db.actor:position()) < distance then
      iana = true
   end
   --[[
   if name_anom == "mil_lager_kamp_1" then
      iana = true
   end
   ]]
   return iana
end

function set_enable_anom(a,b,c,d)
   kamps_info[a].timez = c + d
end

----------------------------------------------------------------------------------------------------------------------
--   Схема лагерь. Чудак(и) у костра.
--   автор: Диденко Руслан (Stohe)
--   TODO:
----------------------------------------------------------------------------------------------------------------------
function printf(fmt, ...)
--   local msg = string.format(fmt, ...)
--   local msg_no_ws = string.gsub(msg, "%s", "_")
--   get_console():execute("dbg:" .. msg_no_ws)
end

kamps = {}
kamp_stalkers = {} -- могут ли сталкеры в лагере юзаться игроком.
-- Объявления итераторов
local k,v,kk,vv = 0,0,0,0
---------------------------------------------------------------------------------------------------------------------
--Evaluators
----------------------------------------------------------------------------------------------------------------------
--' Условие завершения скрипта
class "evaluator_kamp_end" (property_evaluator)
function evaluator_kamp_end:__init(name, storage) super (nil, name)
   self.a = storage
end
function evaluator_kamp_end:evaluate()
   return not xr_logic.is_active(self.object, self.a)
end
--' Находимся ли мы на заданной позиции
class "evaluator_on_position" (property_evaluator)
function evaluator_on_position:__init(name, storage) super (nil, name)
   self.a = storage
end
function evaluator_on_position:evaluate()
    if self.object:level_vertex_id() == self.a.pos_vertex then
      return true
   end
   return false
end
----------------------------------------------------------------------------------------------------------------------
--Actions
----------------------------------------------------------------------------------------------------------------------
--' Идет в заданную область
class "action_go_position" (action_base)
function action_go_position:__init (npc_name,action_name,storage) super (nil,action_name)
   self.a = storage
end
function action_go_position:initialize()
   action_base.initialize(self)
--   self.object:set_node_evaluator()
--   self.object:set_path_evaluator()
   self.object:set_desired_position()
   self.object:set_desired_direction()
   
   self.a.pos_vertex = nil
end
function action_go_position:execute ()
   action_base.execute (self)

   if db.actor then
      if xr_logic.try_switch_to_another_section(self.object, self.a, db.actor) then
         return
      end
   end   
   
   local tmp_pos_vertex = kamps[self.a.center_point]:getDestVertex(self.object:id(), self.a.radius)
   if self.a.pos_vertex ~= tmp_pos_vertex then
      self.a.pos_vertex = tmp_pos_vertex
      
      if not self.object:accessible(self.a.pos_vertex) then
         --'printf("[%s] KAMP NODE NOT ACCESSIBLE. Get accessible nearest", self.object:name())
         local ttp = vector():set(0,0,0)
         self.a.pos_vertex = self.object:accessible_nearest(level.vertex_position(self.a.pos_vertex), ttp)
      end
      
      self.a.pp = patrol(self.a.center_point):level_vertex_id(0)
      self.a.pp = level.vertex_in_direction(self.a.pp, vector():set(math.random(-1,1), 0, math.random(-1,1)), math.random(0,0.5))
      self.object:set_dest_level_vertex_id(self.a.pos_vertex)
      self.object:set_desired_direction(vector():sub(level.vertex_position(self.a.pp),level.vertex_position(self.a.pos_vertex)))
      self.object:set_path_type(game_object.level_path)
      state_mgr.set_state(self.object,"sprint",nil,nil,nil,{animation=true})
   end
end
function action_go_position:finalize ()
   action_base.finalize (self)
end

--' Просто сидит и втыкает
class "action_wait" (action_base)
function action_wait:__init (npc_name,action_name,storage) super (nil,action_name)
   self.a = storage
end
function action_wait:initialize()
   action_base.initialize(self)
--   self.object:set_node_evaluator()
--   self.object:set_path_evaluator()
   self.object:set_desired_position()
   self.object:set_desired_direction()
   
   kamps[self.a.center_point]:increasePops(self.object)
end
function action_wait:activate_scheme()
end
function action_wait:execute()
   action_base.execute (self)
   if db.actor then
      if xr_logic.try_switch_to_another_section(self.object, self.a, db.actor) then
         return
      end
   end
   local state, sound, substate = kamps[self.a.center_point]:updateNpc(self.object)
   
   --' повернуть его лицом к центру
   state_mgr.set_state(self.object, state, nil, nil, {look_position = level.vertex_position(self.a.pp)}, nil, nil, {subanim = substate})
   xr_sound.set_sound(self.object, sound)
end
function action_wait:finalize()
   kamps[self.a.center_point]:decreasePops(self.object)
   action_base.finalize (self)
end
function action_wait:deactivate(npc)
   kamps[self.a.center_point]:removeNpc(npc)
end
function action_wait:death_callback(npc)
   kamps[self.a.center_point]:removeNpc(npc)
end
function action_wait:net_destroy(npc)
   kamps[self.a.center_point]:decreasePops(self.object)   --<< Dynamic campfire mod
   kamps[self.a.center_point]:removeNpc(npc)
end


class "CKampManager"
function CKampManager:__init(path)
   self.kamp_name = path
   self.patrol = patrol(path)
   self.center = self.patrol:level_vertex_id(0)
   self.position = {{dir = vector():set(1, 0, 0),   used = nil},
                {dir = vector():set(1, 0, 1),   used = nil},
                {dir = vector():set(0, 0, 1),   used = nil},
                {dir = vector():set(-1, 0, 1),   used = nil},
                {dir = vector():set(-1, 0, 0),   used = nil},
                {dir = vector():set(-1, 0, -1),used = nil},
                {dir = vector():set(0, 0, -1),   used = nil},
                {dir = vector():set(1, 0, -1),   used = nil}}
   self.npc = {}
   self.population = 0
   self.kamp_state = "idle"   
   -- Где то здесь распарсим патрульный путь и проапдейтим вектор позиций.
   -- 0 вершина - центр лагеря.
   -- 1 флаг - сектор занят, в поинте можно сидеть.
   -- 2 флаг - сектор занят, в поинте нельзя сидеть.
   for k = 1, self.patrol:count() - 1 do
      -- если есть 1 или 2 флажок - отметить сектор как занятый
      if self.patrol:flag(k,1) or
         self.patrol:flag(k,2)
      then
         -- отметить сектор как занятый
         for key,value in pairs(self.position) do
            dir = vector():sub(level.vertex_position(self.patrol:level_vertex_id(k)), level.vertex_position(self.center))
            if value.dir then
               yaw = yaw_degree(dir, value.dir)
               if yaw <=23 then
                  --'printf("KAMP node[%s], sector[%s,] yaw[%s]", k, key, yaw_degree(dir, value.dir))
                  value.used = -1
                  break                  
               end
            end
         end
         
      end
      
      -- если есть 1 флажок - создать место для сидения в точке пути
      if self.patrol:flag(k,1) then
         -- создать точку для сидения
         table.insert(self.position, {vertex = self.patrol:level_vertex_id(k)})
      end      
   end
   --print_table(self.position)
   --Таблица соответствий состояния лагеря и допустимых анимаций и звуков.   
   self.avail_state = {idle            = { directed   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  pre_harmonica      = { directed   = { "wait_harmonica"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  harmonica         = { directed   = { "play_harmonica"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  post_harmonica      = { directed   = { "wait_harmonica"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  pre_guitar         = { directed   = { "wait_guitar"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  guitar            = { directed   = { "play_guitar"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  post_guitar         = { directed   = { "wait_guitar"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  story            = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  post_story         = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  pre_joke         = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  joke            = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}},
                  post_joke         = { directed   = { "declarate"},
                                    undirected   = { "wait", "sit", "sit_ass", "sit_knee", "eat_kolbasa", "eat_vodka", "eat_energy", "eat_bread", "trans"}}}
   self.avail_sound = {idle            = { directed = "idle"},
                  pre_harmonica      = { directed = "pre_harmonica", undirected = ""},
                  harmonica         = { directed = "play_harmonica", undirected = ""},
                  post_harmonica      = { directed = "", undirected = "reac_harmonica"},
                  pre_guitar         = { directed = "pre_guitar", undirected = ""},
                  guitar            = { directed = "play_guitar", undirected = ""},
                  post_guitar         = { directed = "", undirected = "reac_guitar"},
                  story            = { directed = "play_story", undirected = ""},
                  post_story         = { directed = "", undirected = "reac_story"},
                  pre_joke         = { directed = "pre_joke", undirected = ""},
                  joke            = { directed = "play_joke", undirected = ""},
                  post_joke         = { directed = "", undirected = "reac_joke"}}
   -- Таблица таймаутов по состоянию. Если состояние установилось, то некоторое время оно не может быт изменено.                  
   self.timeout    = {idle            = { min = 30000 },
                  pre_harmonica      = { min = 3000 },
                  harmonica         = { min = 5000, soundstart = true },
                  post_harmonica      = { min = 3000 },
                  pre_guitar         = { min = 3000 },
                  guitar            = { min = 5000, soundstart = true },
                  post_guitar         = { min = 3000 },
                  story            = { min = 1000, soundstart = true },
                  post_story         = { min = 3000 },
                  pre_joke         = { min = 3000 },
                  joke            = { min = 5000, soundstart = true },
                  post_joke         = { min = 3000 }}
   -- Таблица глобальных состояний лагеря.
   self.kamp_states = { idle = true,
                   pre_harmonica = false, harmonica = false, post_harmonica = false,
                   pre_guitar = false, guitar = false, post_guitar = false,
                   story = false, post_story = false,
                   pre_joke = true, joke = true, post_joke = true}
   -- Таблица допустимых переходов между состояниями с вероятностями.
   self.trans_kamp = { idle         = { idle = 0, pre_harmonica = 30, pre_guitar = 30, story = 0, pre_joke = 40 },
                  pre_harmonica   = { harmonica = 100 },
                  harmonica      = { post_harmonica = 100 },
                  post_harmonica   = { idle = 70, harmonica = 30 },
                  pre_guitar      = { guitar = 100 },
                  guitar         = { post_guitar = 100 },
                  post_guitar      = { idle = 70, guitar = 30 },
                  story         = { post_story = 100 },
                  post_story      = { idle = 100 },
                  pre_joke      = { joke = 100 },
                  joke         = { post_joke = 100 },
                  post_joke      = { idle = 100 }}
   -- Хранилище для режиссера лагеря. Режиссерем является сталкер, затеявший необычное поведение
   self.director = nil
end
function CKampManager:selectPosition(npc_id)
   -- создаем список доступных позиций
   --printf("KAMP. [%s] called select position", npc_id)
   local free = {}
   for k,v in pairs(self.position) do
      if v.used == nil then
         table.insert(free, k)
      end
   end
   --' затем из доступных позиций выбрать рандомно одну.
   if table.getn(free) > 0 then
      --printf("KAMP [%s] free node > 0", npc_id)
      local rr = math.random(table.getn(free))
      self.position[free[rr]].used = npc_id
      self.npc[npc_id].position = free[rr]
   end
   --printf("KAMP [%s] npc table", npc_id)
   --print_table(self.npc)
   --printf("KAMP [%s] position table", npc_id)
   --print_table(self.position)
end
function CKampManager:getDestVertex(npc_id, radius)
   --printf("get dest Vertex called [%s]", npc_id)
   if self.npc[npc_id].position == nil then
      --printf("-------debug_info-------------")
      --print_table(self.npc)
      --printf("-------debug_info-------------")
      --print_table(self.position)
      --printf("-------debug_info-------------")
      abort("get dest Vertex: nil [%s]", npc_id)
      return nil
   end
   
   local position = self.position[self.npc[npc_id].position]
   if position.vertex ~= nil then
      --printf("vertex preselected [%s]", npc_id)
      return position.vertex
   end
   -- высчитываем вертех по направлению
      local pp = level.vertex_in_direction(self.center, self.position[self.npc[npc_id].position].dir, radius)
      pp = level.vertex_in_direction(pp, vector():set(math.random(-1,1), 0, math.random(-1,1)), math.random(0,0.5))
   --printf("vertex selected [%s]", npc_id)      
   return pp      
end
function CKampManager:proceedState(npc)
   -- Проверка на таймаут
   local npc_id = npc:id()
   local active_sound_count = npc:active_sound_count()
   if self.npc[npc_id].need_sound_begin == true then
      if active_sound_count == 0 then
         return
      else         
         self.npc[npc_id].need_sound_begin = false
      end
   end
   if self.begin ~= nil and
      time_global() - self.begin < self.timeout[self.kamp_state].min
   then
      return
   end

   -- Если режиссер не закончил говорить - ждем конца фразы.
   if active_sound_count > 0 then
      return
   end

   --printf("Proceed state for [%s]", npc_id)
   -- В случае с историей переход обрабатывается отдельно
   if self.kamp_state == "post_story" then
      if self.story_last < self.story_max - 1 then
         self.npc[npc_id].begin = nil
         self.npc[npc_id].need_sound_begin = true
         self.director = npc_id
         self.kamp_state = "story"
         self.begin = time_global()
         for kk,vv in pairs(self.npc) do
            vv.new = true
         end      
         return
      else
         self.selected_story = nil
      end
   end
   -- Определяются допустимые в данный момент переходы.
   local temp = {}
   local max_rnd = 0
   for k,v in pairs(self.trans_kamp[self.kamp_state]) do      
      -- Определяются допустимые состояния для лагеря.
      if self.kamp_states[k] == true then
         temp[k] = v
         max_rnd = max_rnd + v
      end
   end
   -- Осуществляется рандомный взвешенный переход.
   if max_rnd == 0 then
      -- Если переходить некуда - переходим в айдл
      temp["idle"] = 100
      max_rnd = 100
   end
   local p = math.random(0,max_rnd)
   for k,v in pairs(temp) do
      p = p - v
      if p <= 0 then
         --printf("Selected [%s]", k)
         if k == "idle" then
            self.director = nil
            if self.kamp_state ~= "idle" then
               self.npc[npc_id].begin = nil
            end
         else
            self.npc[npc_id].begin = nil
            if self.timeout[k].soundstart == true then
               self.npc[npc_id].need_sound_begin = true
            end
            self.director = npc_id
            self.censor = nil
         end         
         self.kamp_state = k
         self.begin = time_global()
         -- Меняем таймаут для истории
         if k == "post_story" then
            local dep = sound_theme.theme[self.selected_story].depence[self.story_last]
            if dep and dep.min and dep.max then
               self.timeout["post_story"].min = math.random(dep.min, dep.max)*1000
            end
         end
         for kk,vv in pairs(self.npc) do
            vv.new = true
         end
         return
      end
   end
end
function CKampManager:proceedRole(npc, director)
   --printf("Proceed Role for [%s]", npc:id())
   -- Определить список доступных анимаций по состоянию лагеря.
   -- определить список доступных анимаций по наличию предметов
   -- выбрать одну из них (то же самое со звуком).
   local states = 0
   local sound = ""
   local state = ""
   local npc_id = npc:id()
   if self.npc[npc_id].begin == nil or
      time_global() - self.npc[npc_id].begin >= self.npc[npc_id].state_idle
   then
      if director then
         states = self.avail_state[self.kamp_state].directed
         sound = self.avail_sound[self.kamp_state].directed
      else
         states = self.avail_state[self.kamp_state].undirected
         sound = self.avail_sound[self.kamp_state].undirected
      end
      -- Выбирать новое состояние только раз в какое то время.
      local temp = {}
      for k,v in pairs(states) do
         if self.npc[npc_id].states[v] == true then
            table.insert(temp, v)
         end
      end
      
      -- Если мы решили говорить историю, надо выбрать какую именно говорить.
      if sound == "play_story" and self.selected_story == nil and db.story_by_id[npc_id] ~= nil then
         local story_num = table.getn(db.story_by_id[npc_id])
         if story_num > 0 then
            self.selected_story = db.story_by_id[npc_id][math.random(story_num)]
         end         
      end

      self.npc[npc_id].begin = time_global()
      state = temp[math.random(table.getn(temp))]
      self.npc[npc_id].state_selected = state
      self.npc[npc_id].state_idle = math.random(15000,20000)      
   else
      if director then
         sound = self.avail_sound[self.kamp_state].directed
      else
         sound = self.avail_sound[self.kamp_state].undirected
      end
      state = self.npc[npc_id].state_selected   
   end
   --printf("Proceed Role state [%s] sound [%s]", state, sound)   
   return state, sound
end
function CKampManager:updateNpc(npc)
   -- Проверка что сталкер может делать, а что нет.
   self:checkNpcAbility(npc)
   -- Просим лагерь выбрать текущее состояние. Менять состояние лагеря
   -- имеет право только режиссер.
   local npc_id = npc:id()
   local director = self.director == nil or self.director == npc_id
   if director   then
      self:proceedState(npc)
   end
   -- Говорим чудаку выбрать себе состояние для текущего состояния лагеря.
   local state, sound = self:proceedRole(npc, director)
   
   local substate = nil
   if state == "wait_harmonica" then
      if sound == "pre_harmonica" and self.npc[npc_id].new == true then
         xr_sound.set_sound_play(npc, "intro_music", math.random(2000,3000))
         self.npc[npc_id].new = false
      end
      state = "harmonica"
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "play_harmonica" then
      state = "harmonica"
      substate = 1
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "wait_guitar" then
      if sound == "pre_guitar" and self.npc[npc_id].new == true then
         xr_sound.set_sound_play(npc, "intro_music", math.random(2000,3000))
         self.npc[npc_id].new = false
      end
      state = "guitar"
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "play_guitar" then
      state = "guitar"
      substate = 1
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "declarate" then
      if self.npc[npc_id].new == true then
         if sound == "pre_joke" then
            xr_sound.set_sound_play(npc, "intro_joke", math.random(2000,3000))
         elseif sound == "play_joke" then
            xr_sound.set_sound_play(npc, "joke", math.random(2000,3000))
         elseif sound == "play_story" then
            xr_sound.set_sound_play(npc, self.selected_story)
            self.story_last, self.story_max = xr_sound.get_last_IDS(npc, self.selected_story)
         end
         self.npc[npc_id].new = false
      end

      if npc:character_community() == "monolith" then
         local t = math.mod(npc_id, 2)
         if t == 0 then
            state = "trans_0"
         else
            state = "trans_1"
         end
      elseif npc:character_community() == "zombied" then
         state = "trans_zombied"
      else
         local t = math.mod(npc_id, 3)
         if t == 0 then
            state = "sit"
         elseif t == 1 then
            state = "sit_ass"
         else
            state = "sit_knee"
         end
      end
      xr_kamp.kamp_stalkers[npc_id] = false
   elseif state == "trans" then
      if npc:character_community() == "monolith" then
         local t = math.mod(npc_id, 2)
         if t == 0 then
            state = "trans_0"
         else
            state = "trans_1"
         end
      elseif npc:character_community() == "zombied" then
         state = "trans_zombied"
      end
      xr_kamp.kamp_stalkers[npc_id] = false
   else
      xr_kamp.kamp_stalkers[npc_id] = true
   end
   -- Выбор реальных звуков
   if sound == "idle" then
      sound = "weather, state"
   elseif sound == "reac_guitar" then
      sound = "reac_music"
   elseif sound == "reac_harmonica" then
      sound = "reac_music"
   elseif sound == "reac_joke" then
      sound = ""   
      if self.npc[npc_id].new == true then
         if self.censor == nil then
            xr_sound.set_sound_play(npc, "reac_joke", math.random(2000,3000))
            self.censor = npc_id
         else
            xr_sound.set_sound_play(npc, "story_reac_laughter", math.random(100,300))
         end
         self.npc[npc_id].new = false
      end
   elseif sound == "reac_story" then
      sound = ""
      if self.npc[npc_id].new == true then
         local dep = sound_theme.theme[self.selected_story].depence[self.story_last+1]
         if dep then
            if dep.type == "all" then
               xr_sound.set_sound_play(npc, dep.theme, math.random(100,300))
            else
               sound = dep.theme
            end
         end
      end
   elseif sound == "reac_story" then
      sound = ""
   else
      sound = ""
   end

   --printf("Proceed Update Npc [%s] sound [%s]", state, sound)   
   return state, sound, substate
end
function CKampManager:checkNpcAbility(npc)
   local npc_id = npc:id()
   
   if npc:character_community() ~= "monolith" and
      npc:character_community() ~= "zombied"
   then
      -- есть колбасу
      if npc:object("kolbasa") then
         self.npc[npc_id].states["eat_kolbasa"] = true
      else
         self.npc[npc_id].states["eat_kolbasa"] = false
      end
      -- пить водку
      if npc:object("vodka") then
         self.npc[npc_id].states["eat_vodka"] = true
      else
         self.npc[npc_id].states["eat_vodka"] = false
      end
      -- пить енергитический напиток
      if npc:object("energy_drink") then
         self.npc[npc_id].states["eat_energy"] = true
      else
         self.npc[npc_id].states["eat_energy"] = false
      end
      -- есть хлеб
      if npc:object("bread") then
         self.npc[npc_id].states["eat_bread"] = true
      else
         self.npc[npc_id].states["eat_bread"] = false
      end
      -- играть на гармошке
--      if npc:object("harmonica_a") then
--         self.npc[npc_id].states["play_harmonica"] = true
--         self.npc[npc_id].states["wait_harmonica"] = true
--         self.kamp_states["pre_harmonica"] = true
--         self.kamp_states["harmonica"] = true
--         self.kamp_states["post_harmonica"] = true
--      else
         self.npc[npc_id].states["play_harmonica"] = false
         self.npc[npc_id].states["wait_harmonica"] = false
         self.kamp_states["pre_harmonica"] = false
         self.kamp_states["harmonica"] = false
         self.kamp_states["post_harmonica"] = false
--      end
      -- играть на гитаре
      if npc:object("guitar_a") then
         self.npc[npc_id].states["play_guitar"] = true
         self.npc[npc_id].states["wait_guitar"] = true
         self.kamp_states["pre_guitar"] = true
         self.kamp_states["guitar"] = true
         self.kamp_states["post_guitar"] = true
      else
         self.npc[npc_id].states["play_guitar"] = false
         self.npc[npc_id].states["wait_guitar"] = false
         self.kamp_states["pre_guitar"] = false
         self.kamp_states["guitar"] = false
         self.kamp_states["post_guitar"] = false
      end
      -- анекдоты
      if self.population > 1 then
         self.kamp_states["pre_joke"] = true
         self.kamp_states["joke"] = true
         self.kamp_states["post_joke"] = true
      else
         self.kamp_states["pre_joke"] = false
         self.kamp_states["joke"] = false
         self.kamp_states["post_joke"] = false
      end   
   end
   
   -- Если чувак знает истории, надо добавить их к лагерю
--[[
   if self.population > 1 and db.story_by_id[npc:id()] ~= nil then
      self.kamp_states["story"] = true
      self.kamp_states["post_story"] = true
   else
      self.kamp_states["story"] = false
      self.kamp_states["post_story"] = false   
   end
]]
end
function CKampManager:addNpc(npc)
   --printf("KAMP [%s] add npc", npc:name())
   if self.npc[npc:id()] ~= nil then
      --printf("NPC is already exist")
      return
   end
   
   if npc:character_community() == "monolith" or
      npc:character_community() == "zombied"
   then
      self.npc[npc:id()] = {name = npc:name(), position = nil, current = nil, speak = 0, states = {
                        stand_wait = false, sit = false, sit_ass = false, sit_knee = false, declarate = true,
                        eat_kolbasa = false, eat_vodka = false, eat_energy = false, eat_bread = false, trans = true,
                        play_harmonica = false, play_guitar = false, play_joke = false, play_story = false}}
   else
      self.npc[npc:id()] = {name = npc:name(), position = nil, current = nil, speak = 0, states = {
                        stand_wait = true, sit = true, sit_ass = true, sit_knee = true, declarate = true,
                        eat_kolbasa = false, eat_vodka = false, eat_energy = false, eat_bread = false, trans = false,
                        play_harmonica = false, play_guitar = false, play_joke = false, play_story = false}}
   end
   self:selectPosition(npc:id())   
end
function CKampManager:removeNpc(npc)
   --printf("KAMP [%s] remove npc", npc:name())
   local npc_id = npc:id()
   if self.npc[npc_id] ~= nil then
      -- Если удаляем режиссера - необходимо форсированно перевести лагерь в идловое состояние.
      if self.director == npc_id then
         self.director = nil
         self.npc[npc_id].begin = nil
         self.censor = nil
         self.kamp_state = "idle"
         self.begin = time_global()
         for kk,vv in pairs(self.npc) do
            vv.new = true
         end
         xr_sound.set_sound(npc, nil)
         stop_play_sound(npc)
      end
   
      self.position[self.npc[npc_id].position].used = nil
      self.npc[npc_id] = nil
   end
end

-->> Dynamic campfire mod
local camp_tbl = {
   ["esc2_st_fabric_kamp_1"] = {"zone_flame_small_0001", "lights_camp_fire_omni_r1_r2_0001"},
   ["esc_bridge_kamp_point"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0002"},
   ["esc_lager_camp_center"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0004"},
   ["esc_killers_kamp"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0004"},
   ["esc_blokpost_kamp"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["esc2_most_kamp_1"] = {"zone_flame_small_0006", "lights_camp_fire_omni_r1_r2_0006"},
   ["esc_assault_kamp_center1"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["esc_fabrika_bandit_camp_center"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["esc2_st_fabric_kamp_2"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["esc2_bandit_les_kamp_1"] = {"zone_flame_small_0008", "lights_camp_fire_omni_r1_r2_0008"},
   ["esc_stalker_camp_esc_fox_kamp"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["esc2_st_fox_place_kamp_1"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["esc_stalker_camp_camp_point"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},

   ["gar_angar_gar_seryi_kamp"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0003"},
   ["gar_smart_garage_kamp_1"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0003"},
   ["gar_smart_graveyard_kamp_1"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0004"},
   ["gar_bandit_agr_kamp_point1"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0004"},
   ["gar_bandit_agr_kamp_point"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0004"},
   ["gar_hellcar_group_kamp_point"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0004"},
   ["gar_smart_bandit_kamp_1"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0005"},
   ["gar_smart_stalkers_1_kamp_1"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0005"},
   ["gar_dolg_blokpost_kamp_point"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0006"},
   
   ["val_smart_bandit_2_kamp_2"] = {"zone_flame_small_0006", "lights_camp_fire_omni_r1_r2_0006"},
   ["val_smart_bandit_2_kamp_1"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["val_lager_bandits_kamp2"] = {"zone_flame_small_0010", "lights_camp_fire_omni_r1_r2_0010"},
   ["val_lager_bandits_kamp3"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["val_lager_bandits_kamp1"] = {"zone_flame_small_0012", "lights_camp_fire_omni_r1_r2_0012"},
   ["val_smart_bandit_1_kamp_1"] = {"zone_flame_small_0015", "lights_camp_fire_omni_r1_r2_0015"},
   ["val_rob_kamp"] = {"zone_flame_small_0015", "lights_camp_fire_omni_r1_r2_0015"},
   ["val_exit1_ambush_kamp_1"] = {"zone_flame_small_0017", "lights_camp_fire_omni_r1_r2_0017"},
   ["val_smart_bandit_3_kamp_1"] = {"zone_flame_small_0017", "lights_camp_fire_omni_r1_r2_0017"},
   
   ["bar_visitors_kamp_1"] = {"zone_flame_small_0000", "lights_camp_fire_omni_r1_r2_0000"},
   ["bar_visitors_kamp_2"] = {"zone_flame_small_0001", "lights_camp_fire_omni_r1_r2_0001"},
   ["bar_visitors_kamp_3"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["bar_dolg_general_kamp_center"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0003"},
   ["bar_visitors_kamp_4"] = {"zone_flame_small_0004", "lights_camp_fire_omni_r1_r2_0004"},
   
   ["ros_smart_stalker_bandits1_kamp_1"] = {"zone_flame_small_0000", "lights_camp_fire_omni_r1_r2_0000"},
   
   ["yan_st_stalker2_kamp_1"] = {"zone_flame_small_0008", "lights_camp_fire_omni_r1_r2_0008"},
   
   ["mil_monolit_kamp1"] = {"zone_flame_small_0000", "lights_camp_fire_omni_r1_r2_0000"},
   ["mil_fneutral_kamp"] = {"zone_flame_small_0000", "lights_camp_fire_omni_r1_r2_0000"},
   ["mil_monolit_kamp2"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0002"},
   ["mil_khutor_kamp_center"] = {"zone_flame_small_0003", "lights_camp_fire_omni_r1_r2_0003"},
   ["mil_smart_dolg_kamp_kamp_1"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["mil_dolg_camp_center"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["mil_village_kamp"] = {"zone_flame_small_0006", "lights_camp_fire_omni_r1_r2_0006"},
   ["mil_fblockpost_kamp"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["mil_monolit_kamp3"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["mil_lager_kamp_1"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["mil_mercs_kamp_1"] = {"zone_flame_small_0010", "lights_camp_fire_omni_r1_r2_0010"},
   ["mil_bandit_kamp_1"] = {"zone_flame_small_0011", "lights_camp_fire_omni_r1_r2_0011"},
   ["mil_freedom_camp_center1"] = {"zone_flame_small_0012", "lights_camp_fire_omni_r1_r2_0012"},
   
   ["rad_prip_teleport_kamp_center"] = {"zone_flame_small_0001", "lights_camp_fire_omni_r1_r2_0001"},
   ["rad2_prip_teleport_kamp_1"] = {"zone_flame_small_0001", "lights_camp_fire_omni_r1_r2_0001"},
   ["rad_valley_kamp"] = {"zone_flame_small_0002", "lights_camp_fire_omni_r1_r2_0002"},
   ["rad_entrance_kamp"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["rad2_prip_teleport_kamp_2"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["rad_mil_entrance_kamp_center"] = {"zone_flame_small_0005", "lights_camp_fire_omni_r1_r2_0005"},
   ["rad_prip_road_kamp_center"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["rad_freedom_vs_duty_kamp_center1"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["rad_freedom_vs_duty_kamp_center"] = {"zone_flame_small_0007", "lights_camp_fire_omni_r1_r2_0007"},
   ["rad2_loner_0001_kamp_1"] = {"zone_flame_small_0008", "lights_camp_fire_omni_r1_r2_0008"},
   ["rad2_loner_0002_kamp_1"] = {"zone_flame_small_0009", "lights_camp_fire_omni_r1_r2_0009"},
   ["rad_antenna_monolith_kamp"] = {"zone_flame_small_0010", "lights_camp_fire_omni_r1_r2_0010"},
   ["rad_antenna_patrol_kamp"] = {"zone_flame_small_0010", "lights_camp_fire_omni_r1_r2_0010"},
   ["rad2_loner_0000_kamp_1"] = {"zone_flame_small_0013", "lights_camp_fire_omni_r1_r2_0013"},
   
   ["pri_smart_monolith_stalker5_kamp_1"] = {"zone_flame_small_0018", "lights_camp_fire_omni_r1_r2_0005"},
   ["pri_smart_dolg_stalker1_kamp_1"] = {"zone_flame_small_0021", "lights_camp_fire_omni_r1_r2_0008"},
   ["pri_wave7_kamp_1"] = {"pri_zone_flame_small_0003", "pri_r1_r2_0001"},
   ["pri_sideway_left_kamp"] = {"pri_zone_flame_small_0043", "pri_r1_r2_00002"},
   ["pri_smart_freedom_stalker1_kamp_1"] = {"pri_zone_flame_small_0043", "pri_r1_r2_0002"},
   ["pri_smart_monolith_stalker4_kamp_1"] = {"pri_zone_flame_small_0044", "pri_r1_r2_0003"},
   ["pri_monolith_kamp2"] = {"pri_zone_flame_small_0026", "pri_r1_r2_0004"},
   ["pri_monolith_kamp3"] = {"pri_zone_flame_small_0021", "pri_r1_r2_0005"},
   ["pri_monolith_kamp5"] = {"pri_zone_flame_small_0045", "pri_r1_r2_0006"},
   ["pri_monolith_kamp7"] = {"pri_zone_flame_small_0000", "pri_r1_r2_0007"},
   ["pri_smart_monolith_stalker6_kamp_1"] = {"pri_zone_flame_small_0035", "pri_r1_r2_0008"}
}

function CKampManager:increasePops(npc)
   self.population = self.population + 1
   local camp_name = camp_tbl[self.kamp_name]
   local timex = time_global()
   if self.population == 1 and camp_name then
      local flame = camp_name[1]
      local light = camp_name[2]
      
--      kamps_info[self.kamp_name] = nil
--      if not kamps_info[self.kamp_name] then
         kamps_info[self.kamp_name] = {}
         kamps_info[self.kamp_name].time = timex
         kamps_info[self.kamp_name].prtcl = nil
         kamps_info[self.kamp_name].state = nil
--      end
      
      for i,o in pairs(lvl_objs) do
         local obj = o
         if obj and obj:name() == flame then
            kamps_info[self.kamp_name].obj_fire = obj
            set_enable_anom(self.kamp_name,obj,timex,5000)
         end
         if obj and obj:name() == light then
            kamps_info[self.kamp_name].obj_light = obj
         end
      end
   end
end

function CKampManager:decreasePops(npc)
   self.population = self.population - 1
   local camp_name = camp_tbl[self.kamp_name]
   if self.population < 1 and camp_name then
      local flame = camp_name[1]
      local light = camp_name[2]
      
--      if not kamps_info[self.kamp_name] then
         kamps_info[self.kamp_name] = {}
         kamps_info[self.kamp_name].time = time_global()
         kamps_info[self.kamp_name].prtcl = particles_object("explosions\\explosion_01")
         kamps_info[self.kamp_name].state = nil
--      end
      
      for i,o in pairs(lvl_objs) do
         local obj = o
         if obj and obj:name() == flame then
            kamps_info[self.kamp_name].obj_fire = obj
            obj:disable_anomaly()
            kamps_info[self.kamp_name].aenabled = false
         end
         if obj and obj:name() == light then
            kamps_info[self.kamp_name].obj_light = obj
         end
      end
   end
end

function update(time)
   for i,v in pairs(kamps_info) do
      local kamp_name = i
      local kamp_fire = v.obj_fire
      local kamp_light = v.obj_light
      local kamp_time = v.time
      local kamp_prtcl = v.prtcl
      local kamp_state = v.state

      local kamp_timez = v.timez
      local kamp_aon = v.aenabled or false
      
      if kamp_timez ~= nil then
         if kamp_timez > time and not kamp_aon then
            kamps_info[kamp_name].timez = nil
            kamps_info[kamp_name].aenabled = true
            kamp_fire:enable_anomaly()
         end
      end
--[[
      local kamp_restart = v.restart
      local kamp_res_tim = v.restart_timer
      local kamp_fired = v.fired or false
      if is_anomaly_near_actor(i,kamp_fire,125) and not kamp_fired then
            if i == "mil_lager_kamp_1" then
               con("disable_an_anomaly")
               con(i)
            end
         kamp_fire:disable_anomaly()
         kamps_info[kamp_name].fired = true
         kamps_info[kamp_name].restart = true
         kamps_info[kamp_name].restart_timer = time + 5000
      end
      if kamp_restart then
         if kamp_res_tim < time then
            if i == "mil_lager_kamp_1" then
               con("enable_an_anomaly")
               con(i)
            end
            kamps_info[kamp_name].restart = nil
            kamps_info[kamp_name].restart_timer = 0
            kamp_fire:enable_anomaly()
         end
      end
      if not is_anomaly_near_actor(i,kamp_fire,50) then
         kamps_info[kamp_name].fired = false
      end
]]
   end
end
--<< Dynamic campfire mod
----------------------------------------------------------------------------------------------------------------------
--Kamp binder
----------------------------------------------------------------------------------------------------------------------
function add_to_binder(object, ini, scheme, section, storage)
   local operators      = {}
   local properties   = {}

   local manager = object:motivation_action_manager()
   
   properties["kamp_end"]      = xr_evaluators_id.stohe_kamp_base + 1
   properties["on_position"]   = xr_evaluators_id.stohe_kamp_base + 2
   properties["contact"]      = xr_evaluators_id.stohe_meet_base + 1   

   operators["go_position"]   = xr_actions_id.stohe_kamp_base + 1
   operators["wait"]      = xr_actions_id.stohe_kamp_base + 3

   -- Evaluators                                                                           
   manager:add_evaluator (properties["kamp_end"],       this.evaluator_kamp_end      ("kamp_end", storage, "kamp_end"))
   manager:add_evaluator (properties["on_position"],   this.evaluator_on_position   ("kamp_on_position", storage, "kamp_on_position"))

   --printf("PRP %s", stalker_ids.property_script)

   -- Actions
   local action = this.action_wait (object:name(),"action_kamp_wait", storage)
   action:add_precondition      (world_property(stalker_ids.property_alive, true))
   action:add_precondition      (world_property(stalker_ids.property_danger,false))
   action:add_precondition      (world_property(stalker_ids.property_enemy,   false))
   action:add_precondition      (world_property(stalker_ids.property_anomaly,false))
   xr_motivator.addCommonPrecondition(action)
   action:add_precondition      (world_property(properties["on_position"],    true))
   action:add_effect       (world_property(properties["kamp_end"],    true))
   manager:add_action (operators["wait"], action)
   xr_logic.subscribe_action_for_events(object, storage, action)
   
   action = this.action_go_position (object:name(),"action_go_kamp", storage)
   action:add_precondition      (world_property(stalker_ids.property_alive, true))
   action:add_precondition      (world_property(stalker_ids.property_danger,false))
   action:add_precondition      (world_property(stalker_ids.property_enemy,   false))
   action:add_precondition      (world_property(stalker_ids.property_anomaly,false))
   xr_motivator.addCommonPrecondition(action)
   action:add_precondition    (world_property(properties["on_position"],    false))
   action:add_effect       (world_property(properties["on_position"],    true))
   manager:add_action (operators["go_position"], action)

   action = manager:action (xr_actions_id.alife)   
   action:add_precondition      (world_property(properties["kamp_end"],      true))

end
-- включение лагеря
function set_scheme(npc, ini, scheme, section, gulag_name)
   local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)

   st.logic     = xr_logic.cfg_get_switch_conditions(ini, section, npc)      
   
   st.center_point = utils.cfg_get_string(ini, section, "center_point", npc, true,  gulag_name)
   st.radius      = utils.cfg_get_number(ini, section, "radius", npc, false, 2)
   
   if kamps[st.center_point] == nil then
      kamps[st.center_point] = CKampManager(st.center_point)
   end
   kamps[st.center_point]:addNpc(npc)
   st.pos_vertex = nil

   st.def_state_moving = utils.cfg_get_string(ini, section, "def_state_moving", npc, false, "", "walk")
end
Awatar użytkownika
max1071
Stalker

Posty: 135
Dołączenie: 04 Gru 2010, 13:07
Ostatnio był: 09 Cze 2023, 20:21
Frakcja: Wolność
Ulubiona broń: TRs 301
Kozaki: 23


Powróć do Cień Czarnobyla

Kto jest na forum

Użytkownicy przeglądający to forum: Brak zarejestrowanych użytkowników oraz 2 gości