📄 hl1_npc_agrunt.cpp
字号:
SetAbsAngles( angTmp );
AngleVectors( GetAbsAngles(), &vForward, &vRight, NULL );
UTIL_TraceLine( WorldSpaceCenter() + vForward * 128, vecEnemyLKP, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
if ( tr.fraction == 1.0 )
{
GetMotor()->SetIdealYawToTargetAndUpdate ( GetAbsOrigin() + vRight * 128 );
fSkip = TRUE;
TaskComplete();
}
if ( !fSkip )
{
UTIL_TraceLine( WorldSpaceCenter() - vForward * 128, vecEnemyLKP, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
if ( tr.fraction == 1.0 )
{
GetMotor()->SetIdealYawToTargetAndUpdate ( GetAbsOrigin() - vRight * 128 );
fSkip = TRUE;
TaskComplete();
}
}
if ( !fSkip )
{
UTIL_TraceLine( WorldSpaceCenter() + vForward * 256, vecEnemyLKP, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
if ( tr.fraction == 1.0 )
{
GetMotor()->SetIdealYawToTargetAndUpdate ( GetAbsOrigin() + vRight * 256 );
fSkip = TRUE;
TaskComplete();
}
}
if ( !fSkip )
{
UTIL_TraceLine( WorldSpaceCenter() - vForward * 256, vecEnemyLKP, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
if ( tr.fraction == 1.0 )
{
GetMotor()->SetIdealYawToTargetAndUpdate ( GetAbsOrigin() - vRight * 256 );
fSkip = TRUE;
TaskComplete();
}
}
if ( !fSkip )
{
TaskFail( FAIL_NO_COVER );
}
}
else
{
Msg ( "AGRunt - no enemy monster ptr!!!\n" );
TaskFail( FAIL_NO_ENEMY );
}
break;
default:
BaseClass::StartTask ( pTask );
break;
}
}
//=========================================================
// GetSchedule - Decides which type of schedule best suits
// the monster's current state and conditions. Then calls
// monster's member function to get a pointer to a schedule
// of the proper type.
//=========================================================
int CNPC_AlienGrunt::SelectSchedule( void )
{
if ( HasCondition( COND_HEAR_DANGER ) )
{
return SCHED_TAKE_COVER_FROM_BEST_SOUND;
}
switch ( m_NPCState )
{
case NPC_STATE_COMBAT:
{
// dead enemy
if ( HasCondition( COND_ENEMY_DEAD ) )
{
// call base class, all code to handle dead enemies is centralized there.
return BaseClass::SelectSchedule();
}
if ( HasCondition( COND_NEW_ENEMY) )
{
return SCHED_WAKE_ANGRY;
}
// zap player!
if ( HasCondition ( COND_CAN_MELEE_ATTACK1 ) )
{
AttackSound();// this is a total hack. Should be parto f the schedule
return SCHED_MELEE_ATTACK1;
}
if ( HasCondition ( COND_HEAVY_DAMAGE ) )
{
return SCHED_SMALL_FLINCH;
}
// can attack
if ( HasCondition ( COND_CAN_RANGE_ATTACK1 ) && OccupyStrategySlotRange( AGRUNT_SQUAD_SLOT_HORNET1, AGRUNT_SQUAD_SLOT_HORNET2 ) )
{
return SCHED_RANGE_ATTACK1;
}
if ( OccupyStrategySlot ( AGRUNT_SQUAD_SLOT_CHASE ) )
{
return SCHED_CHASE_ENEMY;
}
return SCHED_STANDOFF;
}
}
return BaseClass::SelectSchedule();
}
int CNPC_AlienGrunt::TranslateSchedule( int scheduleType )
{
switch ( scheduleType )
{
case SCHED_TAKE_COVER_FROM_ENEMY:
return SCHED_AGRUNT_TAKE_COVER_FROM_ENEMY;
break;
/*case SCHED_RANGE_ATTACK1:
if ( HasCondition( COND_SEE_ENEMY ) )
return SCHED_AGRUNT_RANGE_ATTACK;
// else
// return SCHED_AGRUNT_HIDDEN_RANGE_ATTACK;
break;*/
case SCHED_STANDOFF:
return SCHED_AGRUNT_STANDOFF;
break;
case SCHED_VICTORY_DANCE:
return SCHED_AGRUNT_VICTORY_DANCE;
break;
case SCHED_FAIL:
// no fail schedule specified, so pick a good generic one.
{
if ( GetEnemy() != NULL )
{
// I have an enemy
// !!!LATER - what if this enemy is really far away and i'm chasing him?
// this schedule will make me stop, face his last known position for 2
// seconds, and then try to move again
return SCHED_AGRUNT_COMBAT_FAIL;
}
return SCHED_AGRUNT_FAIL;
}
break;
}
return BaseClass::TranslateSchedule( scheduleType );
}
void CNPC_AlienGrunt::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
CTakeDamageInfo ainfo = info;
float flDamage = ainfo.GetDamage();
if ( ptr->hitgroup == 10 && (ainfo.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_CLUB)))
{
// hit armor
if ( m_flDamageTime != gpGlobals->curtime || (random->RandomInt(0,10) < 1) )
{
CPVSFilter filter( ptr->endpos );
te->ArmorRicochet( filter, 0.0, &ptr->endpos, &ptr->plane.normal );
m_flDamageTime = gpGlobals->curtime;
}
if ( random->RandomInt( 0, 1 ) == 0 )
{
Vector vecTracerDir = vecDir;
vecTracerDir.x += random->RandomFloat( -0.3, 0.3 );
vecTracerDir.y += random->RandomFloat( -0.3, 0.3 );
vecTracerDir.z += random->RandomFloat( -0.3, 0.3 );
vecTracerDir = vecTracerDir * -512;
Vector vEndPos = ptr->endpos + vecTracerDir;
UTIL_Tracer( ptr->endpos, vEndPos, ENTINDEX( edict() ) );
}
flDamage -= 20;
if (flDamage <= 0)
flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated
ainfo.SetDamage( flDamage );
}
else
{
SpawnBlood( ptr->endpos, BloodColor(), flDamage);// a little surface blood.
TraceBleed( flDamage, vecDir, ptr, ainfo.GetDamageType() );
}
AddMultiDamage( ainfo, this );
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
AI_BEGIN_CUSTOM_NPC( monster_alien_grunt, CNPC_AlienGrunt )
DECLARE_ACTIVITY( ACT_THREAT_DISPLAY )
DECLARE_TASK ( TASK_AGRUNT_SETUP_HIDE_ATTACK )
DECLARE_TASK ( TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE )
DECLARE_SQUADSLOT( AGRUNT_SQUAD_SLOT_HORNET1 )
DECLARE_SQUADSLOT( AGRUNT_SQUAD_SLOT_HORNET2 )
DECLARE_SQUADSLOT( AGRUNT_SQUAD_SLOT_CHASE )
//=========================================================
// Fail Schedule
//=========================================================
DEFINE_SCHEDULE
(
SCHED_AGRUNT_FAIL,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
" TASK_WAIT 2"
" TASK_WAIT_PVS 0"
" "
" Interrupts"
" COND_CAN_RANGE_ATTACK1"
" COND_CAN_MELEE_ATTACK1"
)
//=========================================================
// Combat Fail Schedule
//=========================================================
DEFINE_SCHEDULE
(
SCHED_AGRUNT_COMBAT_FAIL,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
" TASK_WAIT_FACE_ENEMY 2"
" TASK_WAIT_PVS 0"
" "
" Interrupts"
" COND_CAN_RANGE_ATTACK1"
" COND_CAN_MELEE_ATTACK1"
)
//=========================================================
// Standoff schedule. Used in combat when a monster is
// hiding in cover or the enemy has moved out of sight.
// Should we look around in this schedule?
//=========================================================
DEFINE_SCHEDULE
(
SCHED_AGRUNT_STANDOFF,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
" TASK_WAIT_FACE_ENEMY 2"
" "
" Interrupts"
" COND_CAN_RANGE_ATTACK1"
" COND_CAN_MELEE_ATTACK1"
" COND_SEE_ENEMY"
" COND_NEW_ENEMY"
" COND_HEAR_DANGER"
)
//=========================================================
// Suppress
//=========================================================
DEFINE_SCHEDULE
(
SCHED_AGRUNT_SUPPRESS_HORNET,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_RANGE_ATTACK1 0"
)
//=========================================================
// primary range attacks
//=========================================================
DEFINE_SCHEDULE
(
SCHED_AGRUNT_RANGE_ATTACK,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_FACE_ENEMY 0"
" TASK_RANGE_ATTACK1 0"
" "
" Interrupts"
" COND_NEW_ENEMY"
" COND_ENEMY_DEAD"
" COND_HEAVY_DAMAGE"
)
DEFINE_SCHEDULE
(
SCHED_AGRUNT_HIDDEN_RANGE_ATTACK,
" Tasks"
" TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_AGRUNT_STANDOFF"
" TASK_AGRUNT_SETUP_HIDE_ATTACK 0"
" TASK_STOP_MOVING 0"
" TASK_FACE_IDEAL 0"
" TASK_RANGE_ATTACK1_NOTURN 0"
" "
" Interrupts"
" COND_NEW_ENEMY"
" COND_HEAVY_DAMAGE"
" COND_HEAR_DANGER"
)
//=========================================================
// Take cover from enemy! Tries lateral cover before node
// cover!
//=========================================================
DEFINE_SCHEDULE
(
SCHED_AGRUNT_TAKE_COVER_FROM_ENEMY,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_WAIT 0.2"
" TASK_FIND_COVER_FROM_ENEMY 0"
" TASK_RUN_PATH 0"
" TASK_WAIT_FOR_MOVEMENT 0"
" TASK_REMEMBER MEMORY:INCOVER"
" TASK_FACE_ENEMY 0"
" "
" Interrupts"
" COND_NEW_ENEMY"
)
//=========================================================
// Victory dance!
//=========================================================
DEFINE_SCHEDULE
(
SCHED_AGRUNT_VICTORY_DANCE,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_AGRUNT_THREAT_DISPLAY"
" TASK_WAIT 0.2"
" TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE 0"
" TASK_WALK_PATH 0"
" TASK_WAIT_FOR_MOVEMENT 0"
" TASK_FACE_ENEMY 0"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_CROUCH"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_VICTORY_DANCE"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_VICTORY_DANCE"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_STAND"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_THREAT_DISPLAY"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_CROUCH"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_VICTORY_DANCE"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_VICTORY_DANCE"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_VICTORY_DANCE"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_VICTORY_DANCE"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_VICTORY_DANCE"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_STAND"
" "
" Interrupts"
" COND_NEW_ENEMY"
" COND_LIGHT_DAMAGE"
" COND_HEAVY_DAMAGE"
)
//=========================================================
//=========================================================
DEFINE_SCHEDULE
(
SCHED_AGRUNT_THREAT_DISPLAY,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_FACE_ENEMY 0"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_THREAT_DISPLAY"
" "
" Interrupts"
" COND_NEW_ENEMY"
" COND_LIGHT_DAMAGE"
" COND_HEAVY_DAMAGE"
" COND_HEAR_PLAYER"
" COND_HEAR_COMBAT"
" COND_HEAR_WORLD"
)
AI_END_CUSTOM_NPC()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -