Beispiel #1
0
void CMonsterSquadManager::update(CEntity *entity)
{
	CMonsterSquad	*squad = monster_squad().get_squad(entity);
	if (squad && squad->SquadActive() && (squad->GetLeader() == entity)) {
		squad->UpdateSquadCommands();
	}
}
Beispiel #2
0
void CBaseMonster::Die(CObject* who)
{
	if (StateMan) StateMan->critical_finalize();

	m_psy_aura.on_monster_death();
	m_radiation_aura.on_monster_death();
	m_fire_aura.on_monster_death();
	m_base_aura.on_monster_death();

	if ( m_anti_aim )
	{
		m_anti_aim->on_monster_death ();
	}

	inherited::Die(who);

	if (is_special_killer(who))
		sound().play			(MonsterSound::eMonsterSoundDieInAnomaly);
	else
		sound().play			(MonsterSound::eMonsterSoundDie);

	monster_squad().remove_member	((u8)g_Team(),(u8)g_Squad(),(u8)g_Group(),this);

	if ( m_grouping_behaviour )
	{
		m_grouping_behaviour->set_squad(NULL);
	}
	
	
	if (m_controlled)			m_controlled->on_die();
}
void CStateManagerBloodsucker::drag_object()
{
	CEntityAlive* const ph_obj = object->m_cob;
	if ( !ph_obj )
	{
		return;
	}

	IKinematics* const kinematics = smart_cast<IKinematics*>(ph_obj->Visual());
	if ( !kinematics )
	{
		return;
	}

	CMonsterSquad* const squad = monster_squad().get_squad(object);
	if ( squad )
	{
		squad->lock_corpse(ph_obj);
	}

	{
		const u16 drag_bone = kinematics->LL_BoneID(object->m_str_cel);
		object->character_physics_support()->movement()->PHCaptureObject(ph_obj, drag_bone);
	}

	CPHCapture* const capture = object->character_physics_support()->movement()->PHCapture();

	if ( capture && !capture->Failed() && object->is_animated() ) 
	{
		object->start_drag();
	}
}
Beispiel #4
0
void CBaseMonster::ChangeTeam(int team, int squad, int group)
{
	if ((team == g_Team()) && (squad == g_Squad()) && (group == g_Group())) return;

#ifdef DEBUG
	if (!g_Alive()) {
		ai().script_engine().print_stack	();
		VERIFY2								(g_Alive(),"you are trying to change team of a dead entity");
	}
#endif // DEBUG

	// remove from current team
	monster_squad().remove_member	((u8)g_Team(),(u8)g_Squad(),(u8)g_Group(),this);
	inherited::ChangeTeam			(team,squad,group);
	monster_squad().register_member	((u8)g_Team(),(u8)g_Squad(),(u8)g_Group(), this);

	if ( m_grouping_behaviour )
	{
		m_grouping_behaviour->set_squad( monster_squad().get_squad(this) );
	}	
}
BOOL CBaseMonster::net_Spawn (CSE_Abstract* DC) 
{
	if (!inherited::net_Spawn(DC))
		return(FALSE);

	CSE_Abstract							*e	= (CSE_Abstract*)(DC);
	R_ASSERT2								(ai().get_level_graph() && ai().get_cross_table() && (ai().level_graph().level_id() != u32(-1)),"There is no AI-Map, level graph, cross table, or graph is not compiled into the game graph!");
	monster_squad().register_member			((u8)g_Team(),(u8)g_Squad(),(u8)g_Group(), this);
	settings_overrides						();


	if (GetScriptControl()) {
		m_control_manager->animation().reset_data	();
		ProcessScripts						();
	}
	m_pPhysics_support->in_NetSpawn			(e);

	control().update_frame();
	control().update_schedule();

	// spawn inventory item
//	if (ai().get_alife()) {
//		
//		CSE_ALifeMonsterBase					*se_monster = smart_cast<CSE_ALifeMonsterBase*>(ai().alife().objects().object(ID()));
//		VERIFY									(se_monster);
//
//		if (se_monster->m_flags.is(CSE_ALifeMonsterBase::flNeedCheckSpawnItem)) {
//			float prob = Random.randF();
//			if ((prob < m_spawn_probability) || fsimilar(m_spawn_probability,1.f)) 
//				se_monster->m_flags.set(CSE_ALifeMonsterBase::flSkipSpawnItem, FALSE);
//
//			se_monster->m_flags.set(CSE_ALifeMonsterBase::flNeedCheckSpawnItem, FALSE);
//		}
//
//		if (!se_monster->m_flags.is(CSE_ALifeMonsterBase::flSkipSpawnItem)) {
//			CSE_Abstract	*object = Level().spawn_item (m_item_section,Position(),ai_location().level_vertex_id(),ID(),true);
//			CSE_ALifeObject	*alife_object = smart_cast<CSE_ALifeObject*>(object);
//			if (alife_object)
//				alife_object->m_flags.set	(CSE_ALifeObject::flCanSave,FALSE);
//
//			{
//				NET_Packet				P;
//				object->Spawn_Write		(P,TRUE);
//				Level().Send			(P,net_flags(TRUE));
//				F_entity_Destroy		(object);
//			}
//		}
//	}

	return(TRUE);
}
Beispiel #6
0
void CBaseMonster::set_state_sound(u32 type, bool once)
{
	if (once) {
	
		sound().play(type);
	
	} else {

		// handle situation, when monster want to play attack sound for the first time
		if ((type == MonsterSound::eMonsterSoundAggressive) && 
			(m_prev_sound_type != MonsterSound::eMonsterSoundAggressive)) {
			
			sound().play(MonsterSound::eMonsterSoundAttackHit);

		} else {
			// get count of monsters in squad
			u8 objects_count = monster_squad().get_squad(this)->get_count(this, 20.f);

			// include myself
			objects_count++;
			VERIFY(objects_count > 0);

			u32 delay = 0;
			switch (type) {
			case MonsterSound::eMonsterSoundIdle : 
				// check distance to actor

				if (Actor()->Position().distance_to(Position()) > db().m_fDistantIdleSndRange) {
					delay = u32(float(db().m_dwDistantIdleSndDelay) * _sqrt(float(objects_count)));
					type  = MonsterSound::eMonsterSoundIdleDistant;
				} else {
					delay = u32(float(db().m_dwIdleSndDelay) * _sqrt(float(objects_count)));
				}
				
				break;
			case MonsterSound::eMonsterSoundEat:
				delay = u32(float(db().m_dwEatSndDelay) * _sqrt(float(objects_count)));
				break;
			case MonsterSound::eMonsterSoundAggressive:
			case MonsterSound::eMonsterSoundPanic:
				delay = u32(float(db().m_dwAttackSndDelay) * _sqrt(float(objects_count)));
				break;
			}

			sound().play(type, 0, 0, delay);
		} 
	}

	m_prev_sound_type	= type;
}
void CBaseMonster::net_Destroy()
{
	// функция должена быть вызвана перед inherited
	if (m_controlled) m_controlled->on_destroy	();
	if (StateMan) StateMan->critical_finalize	();

	inherited::net_Destroy				();
	
	m_pPhysics_support->in_NetDestroy	();

	monster_squad().remove_member		((u8)g_Team(),(u8)g_Squad(),(u8)g_Group(),this);

#ifdef DEBUG
	m_show_debug_info				= 0;
#endif 

}
void CCoverEvaluator::evaluate_cover(const CCoverPoint *cover_point, float weight)
{
#ifdef DEBUG
	//DBG().level_info(this).add_item(cover_point->position(), D3DCOLOR_XRGB(0,255,0));
#endif
	CMonsterSquad *squad = monster_squad().get_squad(m_object);
	if (squad->is_locked_cover(cover_point->level_vertex_id())) return;

	if (fis_zero(weight))
		return;

	float					dest_distance	= m_dest_position.distance_to(cover_point->position());

	if ((dest_distance <= m_min_distance) && (m_current_distance > dest_distance))
		return;

	if((dest_distance >= m_max_distance) && (m_current_distance < dest_distance))
		return;

	Fvector					direction;
	float					y,p;
	direction.sub			(m_dest_position,cover_point->position());
	direction.getHP			(y,p);

	float					high_cover_value = ai().level_graph().high_cover_in_direction(y,cover_point->level_vertex_id());
	float					low_cover_value = ai().level_graph().low_cover_in_direction(y,cover_point->level_vertex_id());
	float					cover_value = _min(high_cover_value, low_cover_value);
	float					value = cover_value;
	if (ai().level_graph().neighbour_in_direction(direction,cover_point->level_vertex_id()))
		value				+= 10.f;

	value					/= weight;

	if (value >= m_best_value)
		return;

	m_selected				= cover_point;
	m_best_value			= value;
}
Beispiel #9
0
void CAI_Rat::set_dir()
{
	if ((Device.dwTimeGlobal - m_previous_query_time > TIME_TO_GO) || !m_previous_query_time) {
		CMonsterSquad *squad	= monster_squad().get_squad(this);
		Fvector m_enemy_position = memory().enemy().selected()->Position();
		if (squad && squad->SquadActive())
		{
			float m_delta_Angle = angle_normalize((PI * 2) / squad->squad_alife_count());
			float m_heading, m_pitch;
			Fvector m_temp, m_dest_direction;
			m_temp = squad->GetLeader()->Position();
			m_dest_direction.x = (m_temp.x - m_enemy_position.x) / m_temp.distance_to(m_enemy_position);
			m_dest_direction.y = (m_temp.y - m_enemy_position.y) / m_temp.distance_to(m_enemy_position);
			m_dest_direction.z = (m_temp.z - m_enemy_position.z) / m_temp.distance_to(m_enemy_position);
			m_dest_direction.getHP(m_heading, m_pitch);
			m_heading = angle_normalize(m_heading + m_delta_Angle * squad->get_index(this));
			m_dest_direction.setHP(m_heading, m_pitch);
			m_dest_direction.mul(0.5f);
			m_enemy_position.add(m_enemy_position,m_dest_direction);
		}

		m_tGoalDir.set(m_enemy_position);
	}
}
Beispiel #10
0
void CBaseMonster::net_Relcase(CObject *O)
{
	inherited::net_Relcase(O);

	StateMan->remove_links			(O);

	com_man().remove_links			(O);

	// TODO: do not clear, remove only object O
	if (g_Alive()) {
		EnemyMemory.remove_links	(O);
		SoundMemory.remove_links	(O);
		HitMemory.remove_hit_info	(O);

		EnemyMan.remove_links		(O);
		CorpseMan.remove_links		(O);

		UpdateMemory				();
		
		monster_squad().remove_links(O);
	}
	CorpseMemory.remove_links		(O);
	m_pPhysics_support->in_NetRelcase(O);
}
Beispiel #11
0
void   CBaseMonster::add_debug_info (debug::text_tree& root_s)
{
	if ( !g_Alive() )
	{
		return;
	}

	typedef debug::text_tree TextTree;

	//-----------------------------------------------
	// General
	//-----------------------------------------------
	TextTree& general_s = root_s.find_or_add("General");

	detail::add_debug_info(general_s, this);
	TextTree& current_visual_s = general_s.add_line("Current_Visual");
	current_visual_s.add_line(*cNameVisual());

	general_s.add_line("Health", conditions().GetHealth());
	general_s.add_line("Morale", Morale.get_morale());
	general_s.add_line("Angry", m_bAngry);
	general_s.add_line("Growling", m_bGrowling);
	general_s.add_line("Aggressive", m_bAggressive);
	general_s.add_line("Sleep", m_bSleep);

	TextTree& perceptors_s = general_s.find_or_add("Perceptors");
	TextTree& visuals_s = perceptors_s.find_or_add("Visual");

	float object_range, object_fov;
	update_range_fov (object_range,object_fov,eye_range,deg2rad(eye_fov));
	visuals_s.add_line("Eye_Range", object_range);
	visuals_s.add_line("FOV", rad2deg(object_fov));

	CActor* actor = smart_cast<CActor*>(Level().Objects.net_Find(0));
	if ( !actor ) 
	{
		actor = g_debug_actor;
	}

	if ( actor )
	{
		visuals_s.add_line("Actor_Visible",  memory().visual().visible_now(actor));
	}

	//-----------------------------------------------
	// Sounds
	//-----------------------------------------------
	TextTree& sounds_s = perceptors_s.find_or_add("Sounds");
	sounds_s.add_line("Num_Sounds", SoundMemory.GetNumSounds());

	if ( SoundMemory.IsRememberSound() )
	{
		TextTree&   last_s = sounds_s.add_line("Last");

		SoundElem	last_sound;
		bool		last_dangerous;
		SoundMemory.GetSound(last_sound, last_dangerous);
		detail::add_debug_info(last_s, last_sound, last_dangerous);

		if ( SoundMemory.GetNumSounds() > 1 )
		{
			SoundElem	first_sound;
			bool		first_dangerous;
			SoundMemory.GetFirstSound(first_sound, first_dangerous);

			TextTree&   first_s = sounds_s.add_line("First");
			detail::add_debug_info(first_s, first_sound, first_dangerous);
		}
	}
	else
	{
		sounds_s.add_text("no");
	}

	//-----------------------------------------------
	// Hits
	//-----------------------------------------------
	TextTree& hit_s = perceptors_s.add_line("Hits", HitMemory.get_num_hits());
	
	// Hit
	if ( HitMemory.is_hit() ) 
	{
		TextTree& last_hit_object_s = hit_s.add_line("Object");
		detail::add_debug_info(last_hit_object_s, smart_cast<CEntity*>(HitMemory.get_last_hit_object()));
		hit_s.add_line("Time", HitMemory.get_last_hit_time());
		hit_s.add_line("Pos", HitMemory.get_last_hit_position());
		hit_s.add_line("Dir", HitMemory.get_last_hit_dir());
	} 

	//-----------------------------------------------
	// Corpses
	//-----------------------------------------------
	TextTree& corpse_s = general_s.find_or_add("Corpse_Man");

	corpse_s.add_line("Current_Corpse",  CorpseMan.get_corpse() ? 
		                                *CorpseMan.get_corpse()->cName() : "none");
	corpse_s.add_line("Satiety",  make_xrstr("%.2f", GetSatiety()));

	//-----------------------------------------------
	// Group behavious
	//-----------------------------------------------
	TextTree& group_s = general_s.find_or_add("Group_Behaviour");
	group_s.add_line("Team", g_Team());

	TextTree& squad_s = group_s.add_line("Squad",  g_Squad());

	CMonsterSquad* squad = monster_squad().get_squad(this);
	if ( squad )
	{
		squad_s.add_line("SquadActive", squad->SquadActive());
		squad_s.add_line("Im_Leader", squad->GetLeader() == this);
		detail::add_debug_info(squad_s.add_line("Leader"), squad->GetLeader());

		int num_alive = squad->squad_alife_count();
		if ( !num_alive && g_Alive() )
		{
			num_alive++;
		}
		squad_s.add_line("Alive_Count", num_alive);

		TextTree& squad_command_s = squad_s.add_line("My_Squad_Command");
		squad_command_s.add_line("Command_Type", squad->GetCommand(this).type);

		TextTree& squad_goal_s = squad_s.add_line("My_Squad_Goal");
		squad_goal_s.add_line("Goal_Type", squad->GetGoal(this).type);
		detail::add_debug_info(squad_goal_s.add_line("Goal_Entity"), squad->GetGoal(this).entity);
	}

	group_s.add_line("Group", g_Group());

	//-----------------------------------------------
	// Brain (Fsm & Script)
	//-----------------------------------------------
	TextTree& brain_s = root_s.find_or_add("Brain");

	TextTree& fsm_s = brain_s.find_or_add("Fsm");
	StateMan->add_debug_info(fsm_s);

	TextTree& script_control_s = brain_s.add_line("Script_Control_Name");
	if ( !m_bScriptControl )
	{
		script_control_s.add_text("-");
	}
	else
	{
		script_control_s.add_text(GetScriptControlName());

		TextTree& cur_script_action_s = brain_s.add_line("Current_Script_Action");
		if ( m_tpCurrentEntityAction )
		{
			detail::add_debug_info(cur_script_action_s, m_tpCurrentEntityAction);
		}
		else
		{
			cur_script_action_s.add_text("-");
		}

		TextTree& next_script_action_s = brain_s.add_line("Next_Script_Action");
		if ( m_tpActionQueue.size() )
		{
			detail::add_debug_info(next_script_action_s, m_tpActionQueue.front());
		}
		else
		{
			next_script_action_s.add_text("-");
		}
	}

	//-----------------------------------------------
	// Control Manager
	//-----------------------------------------------
	control().add_debug_info( brain_s.add_line("Control_Manager") );

	TextTree& map_home_s = brain_s.add_line("Map_Home");
	map_home_s.add_line("min", Home->get_min_radius());
	map_home_s.add_line("mid", Home->get_mid_radius());
	map_home_s.add_line("max", Home->get_max_radius());
	
	if ( EnemyMan.get_enemy() )
	{
		map_home_s.add_line("Enemy_At_Min", Home->at_min_home( EnemyMan.get_enemy()->Position() ));
		map_home_s.add_line("Enemy_At_Mid", Home->at_mid_home( EnemyMan.get_enemy()->Position() ));
		map_home_s.add_line("Enemy_At_Max", Home->at_home    ( EnemyMan.get_enemy()->Position() ));

		map_home_s.add_line("Dist_To_Enemy", Position().distance_to( EnemyMan.get_enemy()->Position() ));
	}
	
	//-----------------------------------------------
	// Enemies
	//-----------------------------------------------
	TextTree& enemies_s = general_s.find_or_add("Enemies");
	enemies_s.add_text(EnemyMemory.get_enemies_count());

	if ( actor )
	{
		enemies_s.add_line("Actor_Is_Enemy", EnemyMan.is_enemy(actor));
	}

	TextTree& current_enemy_s = enemies_s.find_or_add("Current_Enemy");
	if ( EnemyMan.get_enemy() )
	{
		detail::add_enemy_debug_info(current_enemy_s, this, EnemyMan.get_enemy());
		current_enemy_s.add_line("Time_Last_Seen",  EnemyMan.get_enemy_time_last_seen());
		current_enemy_s.add_line("See_Duration",    EnemyMan.see_enemy_duration());
	}
	else
	{
		current_enemy_s.add_text("0");
	}

	int index = 1;
	for ( ENEMIES_MAP::const_iterator i = EnemyMemory.get_memory().begin(),
		                              e = EnemyMemory.get_memory().end();
		  i!=e; ++i )
	{
		const CEntityAlive* p_enemy = (*i).first;
		if ( p_enemy != EnemyMan.get_enemy() )
		{
			TextTree& enemy_s = enemies_s.add_line(make_xrstr("Enemy %i", index++));
			detail::add_enemy_debug_info(enemy_s, this, p_enemy);
		}			
	}

	//-----------------------------------------------
	// Animations
	//-----------------------------------------------
	TextTree& controller_s = root_s.find_or_add("Controllers");
	TextTree& animation_s = controller_s.find_or_add("Animations");

	TextTree& current_animation_s = animation_s.add_line(*anim().cur_anim_info().name);

	
	CBlend* p_blend = control().animation().current_blend();
	if ( !p_blend )
	{
		p_blend = anim().cur_anim_info().blend;
	}
	
	if ( p_blend )
	{
		detail::add_debug_info(current_animation_s, p_blend);
		current_animation_s.add_line("Script_Animation?", p_blend->motionID == m_tpScriptAnimation);
	}
	else
	{
		current_animation_s.add_text("0");
	}

	//-----------------------------------------------
	// Movement
	//-----------------------------------------------
	TextTree& movement_s = controller_s.find_or_add("Movement");
	movement_s.add_line("Actual",  control().path_builder().actual());
	movement_s.add_line("Enabled",  control().path_builder().enabled());

	CEntityAlive *entity = smart_cast<CEntityAlive *>(Level().CurrentEntity());
	if ( entity && entity->character_physics_support()->movement() ) 
	{
		movement_s.add_line("Velocity",  entity->character_physics_support()->movement()->GetVelocityActual());
	}
	movement_s.add_line("Position").add_line(Position());

	movement_s.add_line("Level_Vertex_ID", ai_location().level_vertex_id());
	movement_s.add_line("Game_Vertex_ID", ai_location().game_vertex_id());

	detail::add_debug_info(movement_s.add_line("Orientation_Current"), 
		                   movement().body_orientation().current);
	detail::add_debug_info(movement_s.add_line("Orientation_Target"), 
		                   movement().body_orientation().target);
	movement_s.add_line("Rotation_Speed", movement().body_orientation().speed);

	const char* pc_path_type = "undefined";
	switch ( movement().path_type() )
	{
		case MovementManager::ePathTypePatrolPath: pc_path_type = "Patrol_Path"; break;
		case MovementManager::ePathTypeGamePath:   pc_path_type = "Game_Path";   break;
		case MovementManager::ePathTypeLevelPath:  pc_path_type = "Level_Path";  break;
	}

	movement_s.add_line("Path_Type", pc_path_type);
	if ( movement().path_type() == MovementManager::ePathTypePatrolPath ) 
	{
		movement_s.add_line("Path_Name", *movement().patrol().path_name());
		movement_s.add_line("Completed",  movement().patrol().completed());

		movement_s.add_line("Current_Point", movement().patrol().get_current_point_index());
		if	( movement().patrol().get_path() && 
			  movement().patrol().get_path()->vertex(movement().patrol().get_current_point_index()) )
		{
			movement_s.add_line("Extrapolate", movement().patrol().extrapolate_path());
		}
		else
		{
			movement_s.add_line("Extrapolate", "unknown");
		}
	}

	if ( movement().path_type() == MovementManager::ePathTypeGamePath ) 
	{
		movement_s.add_line("Completed", movement().game_path().completed());
		movement_s.add_line("Path_Size", movement().game_path().path().size());
		movement_s.add_line("Current_Point", movement().game_path().intermediate_index());
	}

	TextTree& level_s = movement_s.add_line("Level");

	level_s.add_line("Path_Size", movement().level_path().path().size());
	level_s.add_line("Start_Vertex", movement().level_path().path().empty() ? -1 : movement().level_path().path().front());
	level_s.add_line("End_Vertex", movement().level_path().path().empty() ? -1 : movement().level_path().path().back());

	if ( !movement().detail().path().empty() ) 
	{
		TextTree& detail_s = movement_s.add_line("Detail");

		detail_s.add_line("Velocities", movement().detail().velocities().size());
		detail_s.add_line("Extrapolate", movement().detail().extrapolate_length());
		detail_s.add_line("Path_Size", movement().detail().path().size());

		detail_s.add_line("Start_Point").add_line(movement().detail().path().front().position);
		detail_s.add_line("Dest_Point").add_line(movement().detail().path().back().position);
		TextTree& current_point_s = detail_s.add_line("Current_Point");
		current_point_s.add_line("Index", movement().detail().curr_travel_point_index());
		current_point_s.add_line("Position").add_line(movement().detail().path()[movement().detail().curr_travel_point_index()].position);

		CDetailPathManager::STravelParams current_velocity = 
			movement().detail().velocity(movement().detail().path()[movement().detail().curr_travel_point_index()].velocity);
		detail_s.add_line("linear", current_velocity.linear_velocity);
		detail_s.add_line("angular", rad2deg(current_velocity.real_angular_velocity));
		detail_s.add_line("speed(calc)", movement().speed());
		detail_s.add_line("speed(physics)", movement().speed(character_physics_support()->movement()));
	}

	if ( movement().detail().use_dest_orientation() )
	{
		movement_s.add_line("Orientation", movement().detail().dest_direction());
	}
	else
	{
		movement_s.add_line("Orientation", "no");
	}
	
	TextTree& atackdist_s = controller_s.find_or_add("Attack_Distance");
	atackdist_s.add_line("Mind_Dist",  make_xrstr("%.3f", MeleeChecker.get_min_distance()));
	atackdist_s.add_line("Max_Dist",  make_xrstr("%.3f", MeleeChecker.get_max_distance()));
	atackdist_s.add_line("As_Step",  make_xrstr("%.3f", MeleeChecker.dbg_as_step()));
	atackdist_s.add_line("As_MinDist",  make_xrstr("%.3f", MeleeChecker.dbg_as_min_dist()));

	TextTree& restrictions_s = movement_s.add_line("Restrictions");

	if	( movement().restrictions().out_restrictions().size() ||
		  movement().restrictions().in_restrictions().size() ||
		  movement().restrictions().base_out_restrictions().size() ||
		  movement().restrictions().base_in_restrictions().size() )
	{
		detail::add_debug_info_restrictions(restrictions_s.add_line("out"), *movement().restrictions().out_restrictions());
		detail::add_debug_info_restrictions(restrictions_s.add_line("in"), *movement().restrictions().in_restrictions());
		detail::add_debug_info_restrictions(restrictions_s.add_line("base_out"), *movement().restrictions().base_out_restrictions());
		detail::add_debug_info_restrictions(restrictions_s.add_line("base_in"), *movement().restrictions().base_in_restrictions());

		restrictions_s.add_line("Actor_Accessible?", actor ?
			movement().restrictions().accessible(actor->Position()) : false);
	}
	else
	{
		restrictions_s.add_text("-");
	}

	//-----------------------------------------------
	// Sound Player
	//-----------------------------------------------
	TextTree& sound_player_s = controller_s.find_or_add("Sound_Player");
	sound_player_s.add_line("Num_Sounds", sound().objects().size());

	typedef CSoundPlayer::SOUND_COLLECTIONS::const_iterator SoundIterator;

	u32 object_count = 0;
	for ( SoundIterator i=sound().objects().begin(), e=sound().objects().end();
		  i!=e; ++i )
	{
		object_count += (*i).second.second->m_sounds.size();
	}

	TextTree& now_playing_s = sound_player_s.add_line("Objects", object_count);

	typedef xr_vector<CSoundPlayer::CSoundSingle>::const_iterator SoundSingleIterator;

	index = 1;
	for ( SoundSingleIterator i=sound().playing_sounds().begin(), 
		                      e=sound().playing_sounds().end();
		  i!=e; ++i )
	{
		xr_string source = (*i).m_sound->_handle() ? (*i).m_sound->_handle()->file_name() : "no source";

		xr_string status = "not yet started";
		if ( Device.dwTimeGlobal >= (*i).m_start_time )
		{
			status = (*i).m_sound->_feedback() ? "playing" : "already played";
		}

		TextTree& current_sound_s = now_playing_s.add_line(make_xrstr("Sound %i", index++));
		current_sound_s.add_line(source);
		current_sound_s.add_line(status);
	}
}
void CMonsterEnemyMemory::update() 
{
	VERIFY		(monster->g_Alive());

	CMonsterHitMemory& monster_hit_memory = monster->HitMemory;

	typedef CObjectManager<const CEntityAlive>::OBJECTS	objects_list;

	objects_list const& objects	=	monster->memory().enemy().objects();

	if ( monster_hit_memory.is_hit() && time() < monster_hit_memory.get_last_hit_time() + 1000 )
	{
		if ( CEntityAlive* enemy = smart_cast<CEntityAlive*>(monster->HitMemory.get_last_hit_object()) )
		{
			if ( monster->CCustomMonster::useful(&monster->memory().enemy(), enemy) && 
				 monster->Position().distance_to(enemy->Position()) 
				                        < 
				 monster->get_feel_enemy_who_just_hit_max_distance() )
			{
				add_enemy					(enemy);

				bool const self_is_dog	=	!!smart_cast<const CAI_Dog*>(monster);
				if ( self_is_dog )
				{
					CMonsterSquad* const squad	=	monster_squad().get_squad(monster);
					squad->set_home_in_danger	();
				}
			}			
		}
	}

	if ( monster->SoundMemory.IsRememberSound() )
	{
		SoundElem sound;
		bool dangerous;
		monster->SoundMemory.GetSound(sound, dangerous);
		if ( dangerous && Device.dwTimeGlobal < sound.time + 2000 )
		{
			if ( CEntityAlive const* enemy = smart_cast<CEntityAlive const*>(sound.who) )
			{
				float const xz_dist	=	monster->Position().distance_to_xz(g_actor->Position());
				float const y_dist	=	_abs(monster->Position().y - g_actor->Position().y);

				if ( monster->CCustomMonster::useful(&monster->memory().enemy(), enemy) && 
					 y_dist < 10 &&
					 xz_dist < monster->get_feel_enemy_who_made_sound_max_distance() &&
					 g_actor->memory().visual().visible_now(monster)	)
				{
					add_enemy					(enemy);

					bool const self_is_dog	=	!!smart_cast<const CAI_Dog*>(monster);
					if ( self_is_dog )
					{
						CMonsterSquad* const squad	=	monster_squad().get_squad(monster);
						squad->set_home_in_danger	();
					}
				}
			}
		}
	}

	for ( objects_list::const_iterator	I	=	objects.begin();
										I	!=	objects.end(); 
									  ++I	) 
	{
		const CEntityAlive* enemy = *I;
		const bool feel_enemy	  = monster->Position().distance_to(enemy->Position()) 
													< 
									monster->get_feel_enemy_max_distance();

		if ( feel_enemy || monster->memory().visual().visible_now(*I) )
			add_enemy(*I);
	}

	float const feel_enemy_max_distance	=	monster->get_feel_enemy_max_distance();
	if ( g_actor )
	{
		float const xz_dist	=	monster->Position().distance_to_xz(g_actor->Position());
		float const y_dist	=	_abs(monster->Position().y - g_actor->Position().y);

		if ( xz_dist < feel_enemy_max_distance && 
			 y_dist < 10 &&
			 monster->memory().enemy().is_useful(g_actor) &&
			 g_actor->memory().visual().visible_now(monster) )
		{
			add_enemy(g_actor);
		}
	}
	
	// удалить устаревших врагов
	remove_non_actual();

	// обновить опасность 
	for (ENEMIES_MAP_IT it = m_objects.begin(); it != m_objects.end(); it++) {
		u8		relation_value = u8(monster->tfGetRelationType(it->first));
		float	dist = monster->Position().distance_to(it->second.position);
		it->second.danger = (1 + relation_value*relation_value*relation_value) / (1 + dist);
	}
}