max1071 04 gru 2016, 17:53
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"].
Naukowcy
Stalker
Posty: 136
Rejestracja: 04 gru 2010, 13:07
Ostatnio: 20 mar 2026, 17:38
Ulubiona broń: TRs 301
Kozaki:
24
Na górę
Post autor: max1071 
Witajcie.

Mam problem i potrzebuję moda na to by wyłączyć zadawanie obrażeń przez ogniska..
Najemnicy
Legenda
Posty: 1018
Rejestracja: 02 paź 2013, 17:17
Ostatnio: 20 mar 2026, 17:05
Ulubiona broń: SPSA14
Kozaki:
240
Na górę
Post autor: Poldzer 
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.
Naukowcy
Stalker
Posty: 136
Rejestracja: 04 gru 2010, 13:07
Ostatnio: 20 mar 2026, 17:38
Ulubiona broń: TRs 301
Kozaki:
24
Na górę
Post autor: max1071 
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 cały

[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 cały

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 cały

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
AdministratorAdministrator
Posty: 1920
Rejestracja: 13 kwie 2009, 18:52
Ostatnio: 28 maja 2026, 19:27
Lokalizacja: Fraktal
Ulubiona broń: GP 37
Kozaki:
726
Na górę
Post autor: Wheeljack 
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

Kod: Zaznacz cały

 zamiast spojlera, poprawiłem.
Monolit
Posty: 4280
Rejestracja: 27 maja 2012, 10:49
Ostatnio: 28 lis 2017, 19:49
Lokalizacja: Kukle Karakańskie
Ulubiona broń: TOZ34
Kozaki:
853
Na górę
Post autor: Pangia 
Wheeljack pisze: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ą!
Iskra
Człowiek-Artefakt
Posty: 666
Rejestracja: 17 lut 2010, 12:59
Ostatnio: 28 maja 2026, 22:52
Ulubiona broń: "Tunder" 5.45
Kozaki:
210
Na górę
Post autor: Alchemik 
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.
Lizać stópki, niuchać stópki, wielbić stópki.
Powinność
PMG
Redaktor
Posty: 376
Rejestracja: 12 gru 2010, 10:30
Ostatnio: 01 sie 2024, 15:05
Ulubiona broń: Viper 5 9x18
Kozaki:
127
Na górę
Post autor: PMG 
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.
Postawili kozaka za ten post (1):
Naukowcy
Stalker
Posty: 136
Rejestracja: 04 gru 2010, 13:07
Ostatnio: 20 mar 2026, 17:38
Ulubiona broń: TRs 301
Kozaki:
24
Na górę
Post autor: max1071 
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 cały

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 cały

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
Odpowiedz

Podobne tematy