[GpGiki 대문으로]

Half LifeA I


// 몬스터의 state index
typedef enum
{

	MONSTERSTATE_NONE = 0,
	MONSTERSTATE_IDLE,
	MONSTERSTATE_COMBAT,
	MONSTERSTATE_ALERT,
	MONSTERSTATE_HUNT,
	MONSTERSTATE_PRONE,
	MONSTERSTATE_SCRIPT,
	MONSTERSTATE_PLAYDEAD,
	MONSTERSTATE_DEAD

} MONSTERSTATE;

//=========================================================
// These are the schedule types
//=========================================================
typedef enum
{
		SCHED_NONE = 0,
		SCHED_IDLE_STAND,
		SCHED_IDLE_WALK,
		SCHED_WAKE_ANGRY,
		SCHED_WAKE_CALLED,
		SCHED_ALERT_FACE,
		SCHED_ALERT_SMALL_FLINCH,
		SCHED_ALERT_BIG_FLINCH,
		SCHED_ALERT_STAND,
		SCHED_INVESTIGATE_SOUND,
		SCHED_COMBAT_FACE,
		SCHED_COMBAT_STAND,
		SCHED_CHASE_ENEMY,
		SCHED_CHASE_ENEMY_FAILED,
		SCHED_VICTORY_DANCE,
		SCHED_TARGET_FACE,
		SCHED_TARGET_CHASE,
		SCHED_SMALL_FLINCH,
		SCHED_TAKE_COVER_FROM_ENEMY,
		SCHED_TAKE_COVER_FROM_BEST_SOUND,
		SCHED_TAKE_COVER_FROM_ORIGIN,
		SCHED_COWER, // usually a last resort!
		SCHED_MELEE_ATTACK1,
		SCHED_MELEE_ATTACK2,
		SCHED_RANGE_ATTACK1,
		SCHED_RANGE_ATTACK2,
		SCHED_SPECIAL_ATTACK1,
		SCHED_SPECIAL_ATTACK2,
		SCHED_STANDOFF,
		SCHED_ARM_WEAPON,
		SCHED_RELOAD,
		SCHED_GUARD,
		SCHED_AMBUSH,
		SCHED_DIE,
		SCHED_WAIT_TRIGGER,
		SCHED_FOLLOW,
		SCHED_SLEEP,
		SCHED_WAKE,
		SCHED_BARNACLE_VICTIM_GRAB,
		SCHED_BARNACLE_VICTIM_CHOMP,
		SCHED_AISCRIPT,
		SCHED_FAIL,

		LAST_COMMON_SCHEDULE			// Leave this at the bottom
} SCHEDULE_TYPE;

//=========================================================
// These are the shared tasks
//=========================================================
typedef enum
{
		TASK_INVALID = 0,
		TASK_WAIT,
		TASK_WAIT_FACE_ENEMY,
		TASK_WAIT_PVS,
		TASK_SUGGEST_STATE,
		TASK_WALK_TO_TARGET,
		TASK_RUN_TO_TARGET,
		TASK_MOVE_TO_TARGET_RANGE,
		TASK_GET_PATH_TO_ENEMY,
		TASK_GET_PATH_TO_ENEMY_LKP,
		TASK_GET_PATH_TO_ENEMY_CORPSE,
		TASK_GET_PATH_TO_LEADER,
		TASK_GET_PATH_TO_SPOT,
		TASK_GET_PATH_TO_TARGET,
		TASK_GET_PATH_TO_HINTNODE,
		TASK_GET_PATH_TO_LASTPOSITION,
		TASK_GET_PATH_TO_BESTSOUND,
		TASK_GET_PATH_TO_BESTSCENT,
		TASK_RUN_PATH,
		TASK_WALK_PATH,
		TASK_STRAFE_PATH,
		TASK_CLEAR_MOVE_WAIT,
		TASK_STORE_LASTPOSITION,
		TASK_CLEAR_LASTPOSITION,
		TASK_PLAY_ACTIVE_IDLE,
		TASK_FIND_HINTNODE,
		TASK_CLEAR_HINTNODE,
		TASK_SMALL_FLINCH,
		TASK_FACE_IDEAL,
		TASK_FACE_ROUTE,
		TASK_FACE_ENEMY,
		TASK_FACE_HINTNODE,
		TASK_FACE_TARGET,
		TASK_FACE_LASTPOSITION,
		TASK_RANGE_ATTACK1,
		TASK_RANGE_ATTACK2,
		TASK_MELEE_ATTACK1,
		TASK_MELEE_ATTACK2,
		TASK_RELOAD,
		TASK_RANGE_ATTACK1_NOTURN,
		TASK_RANGE_ATTACK2_NOTURN,
		TASK_MELEE_ATTACK1_NOTURN,
		TASK_MELEE_ATTACK2_NOTURN,
		TASK_RELOAD_NOTURN,
		TASK_SPECIAL_ATTACK1,
		TASK_SPECIAL_ATTACK2,
		TASK_CROUCH,
		TASK_STAND,
		TASK_GUARD,
		TASK_STEP_LEFT,
		TASK_STEP_RIGHT,
		TASK_STEP_FORWARD,
		TASK_STEP_BACK,
		TASK_DODGE_LEFT,
		TASK_DODGE_RIGHT,
		TASK_SOUND_ANGRY,
		TASK_SOUND_DEATH,
		TASK_SET_ACTIVITY,
		TASK_SET_SCHEDULE,
		TASK_SET_FAIL_SCHEDULE,
		TASK_CLEAR_FAIL_SCHEDULE,
		TASK_PLAY_SEQUENCE,
		TASK_PLAY_SEQUENCE_FACE_ENEMY,
		TASK_PLAY_SEQUENCE_FACE_TARGET,
		TASK_SOUND_IDLE,
		TASK_SOUND_WAKE,
		TASK_SOUND_PAIN,
		TASK_SOUND_DIE,
		TASK_FIND_COVER_FROM_BEST_SOUND,// tries lateral cover first, then node cover
		TASK_FIND_COVER_FROM_ENEMY,// tries lateral cover first, then node cover
		TASK_FIND_LATERAL_COVER_FROM_ENEMY,
		TASK_FIND_NODE_COVER_FROM_ENEMY,
		TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY,// data for this one is the MAXIMUM acceptable distance to the cover.
		TASK_FIND_FAR_NODE_COVER_FROM_ENEMY,// data for this one is there MINIMUM aceptable distance to the cover.
		TASK_FIND_COVER_FROM_ORIGIN,
		TASK_EAT,
		TASK_DIE,
		TASK_WAIT_FOR_SCRIPT,
		TASK_PLAY_SCRIPT,
		TASK_ENABLE_SCRIPT,
		TASK_PLANT_ON_SCRIPT,
		TASK_FACE_SCRIPT,
		TASK_WAIT_RANDOM,
		TASK_WAIT_INDEFINITE,
		TASK_STOP_MOVING,
		TASK_TURN_LEFT,
		TASK_TURN_RIGHT,
		TASK_REMEMBER,
		TASK_FORGET,
		TASK_WAIT_FOR_MOVEMENT,			// wait until MovementIsComplete()
		LAST_COMMON_TASK, // LEAVE THIS AT THE BOTTOM!! (sjb)
} SHARED_TASKS;

// an array of tasks is a task list
// an array of schedules is a schedule list
struct Task_t
{

	int		iTask;
	float	flData;
};

struct Schedule_t
{

	Task_t	*pTasklist;
	int		cTasks;
	int		iInterruptMask;// a bit mask of conditions that can interrupt this schedule

	// a more specific mask that indicates which TYPES of sounds will interrupt the schedule in the
	// event that the schedule is broken by COND_HEAR_SOUND
	int		iSoundMask;
	const	char *pName;
};

// 추측컨데 Task는 일련의 세부적인 항목을 Schedule은 여러개의 Task를 포함한 행동들을 나타낸다고
생각됩니다. 이런 식으로 세부행동과 그 세부행동을 포괄할 수 있는 개념의 Schedule과 같은 형식으로
정리를 한다면 하위 개념의 애니메이션을 일목 요연하게 패턴화해서 적용할 수 있다고 생각합니다.

//Schedule과 Task의 사용 예
//=========================================================
// AI Schedules Specific to talking monsters
//=========================================================

Task_t	tlIdleResponse[] =
{
	{ TASK_SET_ACTIVITY,	(float)ACT_IDLE	},// Stop and listen
	{ TASK_WAIT,			(float)0.5		},// Wait until sure it's me they are talking to
	{ TASK_TLK_EYECONTACT,	(float)0		},// Wait until speaker is done
	{ TASK_TLK_RESPOND,		(float)0		},// Wait and then say my response
	{ TASK_TLK_IDEALYAW,	(float)0		},// look at who I'm talking to
	{ TASK_FACE_IDEAL,		(float)0		},
	{ TASK_SET_ACTIVITY,	(float)ACT_SIGNAL3	},
	{ TASK_TLK_EYECONTACT,	(float)0		},// Wait until speaker is done
};

Schedule_t	slIdleResponse[] =
{
	{
		tlIdleResponse,
		ARRAYSIZE ( tlIdleResponse ),
		bits_COND_NEW_ENEMY		|
		bits_COND_LIGHT_DAMAGE	|
		bits_COND_HEAVY_DAMAGE,
		0,
		"Idle Response"

	},
};

//=========================================================

// Monster Think - calls out to core AI functions and handles this

// monster's specific animation events

//=========================================================

void CBaseMonster :: MonsterThink ( void )
{
	pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking. 판단시간을 지연시켜준다.

	RunAI();

	float flInterval = StudioFrameAdvance( ); // animate
// start or end a fidget

// This needs a better home -- switching animations over time should be encapsulated on a per-activity basis

// perhaps MaintainActivity() or a ShiftAnimationOverTime() or something.

	if ( m_MonsterState != MONSTERSTATE_SCRIPT && m_MonsterState != MONSTERSTATE_DEAD && m_Activity == ACT_IDLE && m_fSequenceFinished )
	{
		int iSequence;

		if ( m_fSequenceLoops )
		{
			// animation does loop, which means we're playing subtle idle. Might need to
			// fidget.
			iSequence = LookupActivity ( m_Activity );
		}
		else
		{
			// animation that just ended doesn't loop! That means we just finished a fidget
			// and should return to our heaviest weighted idle (the subtle one)
			iSequence = LookupActivityHeaviest ( m_Activity );
		}
		if ( iSequence != ACTIVITY_NOT_AVAILABLE )
		{
			pev->sequence = iSequence;	// Set to new anim (if it's there)
			ResetSequenceInfo( );
		}
	}

	DispatchAnimEvents( flInterval );

	if ( !MovementIsComplete() )
	{
		Move( flInterval );
	}
#if _DEBUG
	else
	{
		if ( !TaskIsRunning() && !TaskIsComplete() )
			ALERT( at_error, "Schedule stalled!!
" );
	}
#endif
}


제일 위로
최종 수정 일시: 06월 13일(2001년) 02:13 PM 편집 | 정보 | 차이 | 비슷한 페이지 DebugInfo
유용한 페이지들: 분류 분류 | 자유로운 연습장 SandBox | 무작위 페이지들 RandomPages | 인기있는 페이지들 MostPopular