--[[----------------------------------------------------------------------------------------------------------
Боевая схема сталкеров группировки "Монолит"
Чугай Александр
------------------------------------------------------------------------------------------------------------]]

local base = xr_evaluators_id.combat_monolith_base
local prop_enable = base + 0
local prop_see    = base + 1
local prop_close  = base + 2
local prop_on_pos = base + 3

base = xr_actions_id.combat_monolith_base
local act_fight_close = base + 0
local act_fight_far   = base + 1
local act_look_around = base + 2
local act_go_to_pos   = base + 3

--------------------------------------------------------------------------------------------------------------
class "evaluator_combat_monolith" ( property_evaluator )

function evaluator_combat_monolith:__init( name, storage ) super ( nil, name )
	self.st = storage
end

function evaluator_combat_monolith:evaluate()
	return db.storage[self.object:id()].script_combat_type == "monolith"
end

--------------------------------------------------------------------------------------------------------------
class "evaluator_see" ( property_evaluator )

function evaluator_see:__init( name, storage ) super ( nil, name )
	self.st = storage
end

function evaluator_see:evaluate()
	local be = self.object:best_enemy()

	if self.object:alive() and be and self.object:see( be ) then
		self.st.last_seen_vert_id = be:level_vertex_id()
		return true
	else
		return false
	end
end

--------------------------------------------------------------------------------------------------------------
class "evaluator_close" ( property_evaluator )

function evaluator_close:__init( name, storage ) super ( nil, name )
	self.st = storage
	self.close_dist_sqr = math.random( 20*20, 35*35 )
end

function evaluator_close:evaluate()
	local be = self.object:best_enemy()
	return be ~= nil and self.object:position():distance_to_sqr( be:position() ) < self.close_dist_sqr
end

--------------------------------------------------------------------------------------------------------------
class "evaluator_on_pos" ( property_evaluator )

function evaluator_on_pos:__init( name, storage ) super ( nil, name )
	self.st = storage
end

function evaluator_on_pos:evaluate()
	local r = self.object:level_vertex_id() == self.st.last_seen_vert_id
	--printf( tostring( r ) )
	return r
end

--------------------------------------------------------------------------------------------------------------
class "action_fight_close" ( action_base )

function action_fight_close:__init( name, storage )  super ( nil, name )
	self.st = storage
end

function action_fight_close:initialize()
	action_base.initialize( self )

	state_mgr.set_state( self.object, "hide_fire", nil, nil, { look_object = self.object:best_enemy() } )
end

function action_fight_close:execute()
	action_base.execute( self )
end

function action_fight_close:finalize()
	action_base.finalize( self )
end

-- Внимание: вызывается во всех actions
function action_fight_close:hit_callback( obj, amount, local_direction, who, bone_index )
	if who == nil then	
		return
	end

	local be = self.object and self.object:best_enemy()

	-- если получили хит от текущего врага, то мы знаем, где он
	if be and who:id() == be:id() then
		self.st.last_seen_vert_id = be:level_vertex_id()
	end
end

--------------------------------------------------------------------------------------------------------------
class "action_fight_far" ( action_base )

function action_fight_far:__init( name, storage )  super ( nil, name )
	self.st = storage
end

function action_fight_far:initialize()
	action_base.initialize( self )

--	self.object:set_node_evaluator      ()
--	self.object:set_path_evaluator      ()
	self.object:set_desired_direction   ()
	self.object:set_desired_position    ()
	self.object:set_detail_path_type    ( move.line )
	self.object:set_path_type           ( game_object.level_path )

	state_mgr.set_state( self.object, "assault_fire", nil, nil, { look_object = self.object:best_enemy() } )
end

function action_fight_far:execute()
	action_base.execute( self )

	utils.send_to_nearest_accessible_vertex( self.object, self.object:best_enemy():level_vertex_id() )
end

function action_fight_far:finalize()
	action_base.finalize( self )
end

--------------------------------------------------------------------------------------------------------------
class "action_look_around" ( action_base )

function action_look_around:__init( name, storage )  super ( nil, name )
	self.st = storage
end

function action_look_around:initialize()
	action_base.initialize( self )

	self.forget_time     = time_global() + 30000
	self.change_dir_time = 0
end

function action_look_around:execute()
	action_base.execute( self )

	if self.forget_time < time_global() then
		printf("pl:Disabling_memory_object[9]")
		self.object:enable_memory_object( self.object:best_enemy(), false )

		self.st.last_seen_vert_id = nil

		return
	end

	if self.change_dir_time < time_global() then
		self.change_dir_time = time_global() + math.random( 1000, 2000 )

		local ang = math.rad( math.random( 0, 359 ) )
		local pos = self.object:position():add( vector():set( math.cos( ang ), 0, math.sin( ang ) ) )

		state_mgr.set_state( self.object, "hide", nil, nil, { look_position = pos } )
	end
end

function action_look_around:finalize()
	action_base.finalize( self )
end

--------------------------------------------------------------------------------------------------------------
class "action_go_to_pos" ( action_base )

function action_go_to_pos:__init( name, storage )  super ( nil, name )
	self.st = storage
	self.t  = {}
end

function action_go_to_pos:initialize()
	action_base.initialize( self )

	if not self.st.last_seen_vert_id then
		self.st.last_seen_vert_id = self.object:best_enemy():level_vertex_id()
	end

--	self.object:set_node_evaluator      ()
--	self.object:set_path_evaluator      ()
	self.object:set_desired_direction   ()
	self.object:set_desired_position    ()
	self.object:set_detail_path_type    ( move.line )
	self.object:set_path_type           ( game_object.level_path )

	state_mgr.set_state( self.object, "assault" )

	self.cached_id = -1
end

function action_go_to_pos:execute()
	action_base.execute( self )

	if self.st.last_seen_vert_id ~= self.cached_id then
		self.cached_id = self.st.last_seen_vert_id

		self.st.last_seen_vert_id = utils.send_to_nearest_accessible_vertex( self.object, self.cached_id )
	end
end

function action_go_to_pos:finalize()
	action_base.finalize( self )
end

--------------------------------------------------------------------------------------------------------------
function add_to_binder( npc, ini, st, planner )
--[[	planner:add_evaluator( xr_evaluators_id.combat_monolith_base, evaluator_combat_monolith( "combat_monolith", st ) )

	local action = action_zombie_shoot( "action_zombie_shoot", st )
	action:add_precondition( world_property( xr_evaluators_id.combat_monolith_base, true  ) )
	action:add_effect      ( world_property( stalker_ids.property_enemy,           false ) )
	planner:add_action( xr_actions_id.combat_monolith_base, action )]]

	planner:add_evaluator( prop_enable,    evaluator_combat_monolith( "combat_monolith",        st ) )
	planner:add_evaluator( prop_see,       evaluator_see            ( "combat_monolith_see",    st ) )
	planner:add_evaluator( prop_close,     evaluator_close          ( "combat_monolith_close",  st ) )
	planner:add_evaluator( prop_on_pos,    evaluator_on_pos         ( "combat_monolith_on_pos", st ) )

	local action = action_fight_close( "combat_monolith_fight_close", st )
	action:add_precondition( world_property( stalker_ids.property_alive,     true  ) )
	action:add_precondition( world_property( stalker_ids.property_enemy,     true  ) )
	action:add_precondition( world_property( stalker_ids.property_anomaly,   false ) )
	action:add_precondition( world_property( xr_evaluators_id.script_combat, true  ) )
	action:add_precondition( world_property( prop_enable,                    true  ) )
	action:add_precondition( world_property( prop_see,                       true  ) )
	action:add_precondition( world_property( prop_close,                     true  ) )
	action:add_effect      ( world_property( stalker_ids.property_enemy,     false ) )
	planner:add_action( act_fight_close, action )

	-- подписываем один, работает во всех!
	xr_logic.subscribe_action_for_events( npc, st, action )

	action = action_fight_far( "combat_monolith_fight_far", st )
	action:add_precondition( world_property( stalker_ids.property_anomaly,   false ) )
	action:add_precondition( world_property( prop_close,   false ) )
	action:add_precondition( world_property( prop_see,     true  ) )
	action:add_effect      ( world_property( prop_close,   true  ) )
	planner:add_action( act_fight_far, action )

	action = action_look_around( "combat_monolith_look_around", st )
	action:add_precondition( world_property( stalker_ids.property_anomaly,   false ) )
	action:add_precondition( world_property( prop_on_pos,  true  ) )
	action:add_precondition( world_property( prop_see,     false ) )
	action:add_effect      ( world_property( prop_see,     true  ) )
	planner:add_action( act_look_around, action )

	action = action_go_to_pos( "combat_monolith_go_to_pos", st )
	action:add_precondition( world_property( stalker_ids.property_anomaly,   false ) )
	action:add_precondition( world_property( prop_on_pos,  false ) )
	action:add_effect      ( world_property( prop_on_pos,  true  ) )
	planner:add_action( act_go_to_pos, action )
end
