You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
715 lines
15 KiB
715 lines
15 KiB
2 years ago
|
/************************************************************
|
||
|
* *
|
||
|
* Sniper, par Julien *
|
||
|
* *
|
||
|
************************************************************/
|
||
|
|
||
|
|
||
|
#include "extdll.h"
|
||
|
#include "util.h"
|
||
|
#include "cbase.h"
|
||
|
#include "monsters.h"
|
||
|
#include "schedule.h"
|
||
|
#include "weapons.h"
|
||
|
#include "soundent.h"
|
||
|
#include "animation.h"
|
||
|
#include "effects.h"
|
||
|
|
||
|
|
||
|
|
||
|
#define SNIPER_MAX_CLIP 5
|
||
|
|
||
|
// d
|
||
|
|
||
|
#define HEAD_GROUP 1
|
||
|
#define ARM_L_GROUP 3
|
||
|
#define ARM_R_GROUP 4
|
||
|
#define LEG_L_GROUP 5
|
||
|
#define LEG_R_GROUP 6
|
||
|
|
||
|
#define NO_MEMBRE 1
|
||
|
|
||
|
#define HEAD1 0
|
||
|
#define HEAD2 1
|
||
|
#define HEAD3 2
|
||
|
#define NO_HEAD 3
|
||
|
|
||
|
//=====================================================
|
||
|
// Monster's anim events
|
||
|
// Constantes associ
|
||
|
//=====================================================
|
||
|
|
||
|
#define SNIPER_AE_RELOAD ( 1 )
|
||
|
#define SNIPER_AE_MELEE_ATTACK1 ( 2 )
|
||
|
#define SNIPER_AE_SHOOT ( 3 )
|
||
|
#define SNIPER_AE_DROPGUN ( 4 )
|
||
|
|
||
|
//=====================================================
|
||
|
// Schedule types :
|
||
|
// Attitudes
|
||
|
//=====================================================
|
||
|
enum
|
||
|
{
|
||
|
SCHED_SNIPER_RECHARGEMENT = LAST_COMMON_SCHEDULE + 1,
|
||
|
SCHED_SNIPER_COVER,
|
||
|
};
|
||
|
|
||
|
//=====================================================
|
||
|
//D
|
||
|
//=====================================================
|
||
|
|
||
|
|
||
|
class CSniper : public CBaseMonster
|
||
|
{
|
||
|
public:
|
||
|
void Spawn ( void ); // initialisation
|
||
|
void Precache ( void ); // on pr
|
||
|
void SetYawSpeed ( void ); //vitesse de rotation
|
||
|
int Classify ( void ); // "camp" du monstre : alien ou humain
|
||
|
int IRelationship ( CBaseEntity *pTarget );
|
||
|
|
||
|
void Shoot (void); // le tir !
|
||
|
CBaseEntity *Kick ( void ); // trace un vecteur et voit s'il touche qqn
|
||
|
|
||
|
BOOL CheckRangeAttack1 ( float flDot, float flDist );
|
||
|
BOOL CheckMeleeAttack1 ( float flDot, float flDist );
|
||
|
|
||
|
void CheckAmmo ( void ); // v
|
||
|
|
||
|
void HandleAnimEvent( MonsterEvent_t *pEvent );
|
||
|
void RunTask ( Task_t *pTask );
|
||
|
|
||
|
void GibMonster ( void );
|
||
|
|
||
|
Schedule_t *GetSchedule( void ); // analyse des bit_COND_ ...
|
||
|
Schedule_t *GetScheduleOfType ( int Type ); // ... et en retourne un comportement
|
||
|
|
||
|
int m_cAmmoLoaded; // nbre de balles dans le chargeur du sniper
|
||
|
int m_iShell;
|
||
|
|
||
|
CUSTOM_SCHEDULES; // d
|
||
|
|
||
|
static TYPEDESCRIPTION m_SaveData[];
|
||
|
int Save( CSave &save );
|
||
|
int Restore( CRestore &restore );
|
||
|
|
||
|
void MakeGib ( int body, entvars_t *pevAttacker );
|
||
|
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
|
||
|
|
||
|
virtual Activity GetDeathActivity ( void );
|
||
|
};
|
||
|
LINK_ENTITY_TO_CLASS( monster_sniper, CSniper );
|
||
|
|
||
|
|
||
|
TYPEDESCRIPTION CSniper::m_SaveData[] =
|
||
|
{
|
||
|
DEFINE_FIELD( CSniper, m_cAmmoLoaded, FIELD_INTEGER ),
|
||
|
};
|
||
|
IMPLEMENT_SAVERESTORE( CSniper, CBaseMonster );
|
||
|
|
||
|
|
||
|
int CSniper :: Classify ( void )
|
||
|
{
|
||
|
return CLASS_HUMAN_MILITARY; // copain avec les grunts
|
||
|
}
|
||
|
|
||
|
//====================
|
||
|
|
||
|
void CSniper :: SetYawSpeed ( void )
|
||
|
{
|
||
|
/*int ys;
|
||
|
|
||
|
switch ( m_Activity )
|
||
|
{
|
||
|
case ACT_IDLE:
|
||
|
default:
|
||
|
ys = 50;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pev->yaw_speed = ys;*/
|
||
|
pev->yaw_speed = 360; // rotation en degr
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------
|
||
|
//
|
||
|
// Spawn / Precache
|
||
|
//
|
||
|
//------------------------------------------
|
||
|
|
||
|
void CSniper :: Spawn()
|
||
|
{
|
||
|
Precache( );
|
||
|
|
||
|
SET_MODEL(ENT(pev), "models/sniper.mdl"); // model
|
||
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); // taille de la "boite" : constante pour taille standart
|
||
|
|
||
|
pev->solid = SOLID_SLIDEBOX; // la "boite" est solide
|
||
|
pev->movetype = MOVETYPE_STEP; // il ne vole pas
|
||
|
m_bloodColor = BLOOD_COLOR_RED; // couleur du sang
|
||
|
pev->health = 75; // vie (plus tard avec le skill.cfg)
|
||
|
pev->view_ofs = Vector ( 0, 0, 73 ); // position of the eyes relative to monster's origin.
|
||
|
m_flFieldOfView = VIEW_FIELD_FULL; // c
|
||
|
m_MonsterState = MONSTERSTATE_NONE; // ?
|
||
|
|
||
|
m_HackedGunPos = Vector( 0, 24, 48 ); // position du gun
|
||
|
m_cAmmoLoaded = SNIPER_MAX_CLIP; // nbre de balles dans le chargeur (provisoire)
|
||
|
ClearConditions(bits_COND_NO_AMMO_LOADED);
|
||
|
|
||
|
m_afCapability = bits_CAP_HEAR |
|
||
|
bits_CAP_RANGE_ATTACK1 | // capable d'entendre, et deux attaques
|
||
|
bits_CAP_MELEE_ATTACK1 ;
|
||
|
pev->effects = 0; // pour le muzzleflash ?
|
||
|
|
||
|
MonsterInit(); // ?
|
||
|
|
||
|
m_flDistTooFar = 4096.0;
|
||
|
m_flDistLook = 4096.0;
|
||
|
|
||
|
SetBodygroup ( HEAD_GROUP, RANDOM_LONG(0,2) ); // t
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void CSniper :: Precache()
|
||
|
{
|
||
|
PRECACHE_MODEL("models/sniper.mdl");
|
||
|
PRECACHE_MODEL("models/sniper_gibs.mdl");
|
||
|
|
||
|
PRECACHE_SOUND("weapons/fsniper_shoot1.wav");
|
||
|
|
||
|
m_iShell = PRECACHE_MODEL ("models/sniper_shell.mdl");
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------
|
||
|
//
|
||
|
// Shoot / Kick
|
||
|
//
|
||
|
//------------------------------------------
|
||
|
|
||
|
|
||
|
|
||
|
void CSniper :: Shoot ( void )
|
||
|
{
|
||
|
if (m_hEnemy == NULL)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Vector vecShootOrigin = GetGunPosition();
|
||
|
Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
|
||
|
|
||
|
float m_flDiviation = 0; // perfect shot
|
||
|
UTIL_MakeVectors ( pev->angles );
|
||
|
|
||
|
Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40);
|
||
|
EjectBrass ( pev->origin + gpGlobals->v_up * 32 + gpGlobals->v_forward * 12, vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL);
|
||
|
|
||
|
FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_3DEGREES, 4096, 0, 0, 45 );
|
||
|
|
||
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/fsniper_shoot1.wav", RANDOM_FLOAT(0.6, 0.8), ATTN_NORM);
|
||
|
|
||
|
m_cAmmoLoaded -- ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CBaseEntity *CSniper :: Kick( void )
|
||
|
{
|
||
|
TraceResult tr;
|
||
|
|
||
|
UTIL_MakeVectors( pev->angles ); // == d
|
||
|
Vector vecStart = pev->origin; // le vecteur part de l'origine
|
||
|
vecStart.z += pev->size.z * 0.5; // du monstre et de la moiti
|
||
|
// de la hauteur de la "boite"
|
||
|
Vector vecEnd = vecStart + (gpGlobals->v_forward * 70); // jusqu'
|
||
|
|
||
|
UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); // on trace ce vecteur
|
||
|
|
||
|
if ( tr.pHit ) //
|
||
|
{
|
||
|
CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );
|
||
|
return pEntity;
|
||
|
}
|
||
|
|
||
|
return NULL; // si c'est un coup
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------
|
||
|
// IRelationship
|
||
|
//
|
||
|
//-----------------------------------------
|
||
|
|
||
|
int CSniper::IRelationship ( CBaseEntity *pTarget )
|
||
|
{
|
||
|
if ( FClassnameIs( pTarget->pev, "monster_gargantua" ) )
|
||
|
{
|
||
|
return R_NM;
|
||
|
}
|
||
|
|
||
|
if ( FClassnameIs( pTarget->pev, "vehicle_tank" ) )
|
||
|
{
|
||
|
return R_NO;
|
||
|
}
|
||
|
|
||
|
return CBaseMonster::IRelationship( pTarget );
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------
|
||
|
//
|
||
|
// CheckAttacks -
|
||
|
//------------------------------------------.
|
||
|
|
||
|
void CSniper :: GibMonster ( void )
|
||
|
{
|
||
|
if ( GetBodygroup( 2 ) != 0 )
|
||
|
return;
|
||
|
|
||
|
Vector vecGunPos = GetGunPosition();
|
||
|
Vector vecGunAngles;
|
||
|
|
||
|
Vector zeroVector(0,0,0);
|
||
|
GetAttachment( 0, zeroVector, vecGunAngles );
|
||
|
DropItem( "weapon_fsniper", vecGunPos, vecGunAngles );
|
||
|
|
||
|
CBaseMonster :: GibMonster();
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------
|
||
|
//
|
||
|
// D
|
||
|
//------------------------------------------.
|
||
|
|
||
|
|
||
|
void CSniper :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
|
||
|
{
|
||
|
CBaseMonster :: TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
|
||
|
|
||
|
if ( gMultiDamage.pEntity != this )
|
||
|
return;
|
||
|
|
||
|
if ( ( pev->health - ( gMultiDamage.amount ) <= 0 ) && IsAlive() && m_iHasGibbed == 0 )
|
||
|
{
|
||
|
if ( ptr->iHitgroup == HITGROUP_CHEST )
|
||
|
{
|
||
|
ptr->iHitgroup = RANDOM_LONG ( 1,3 );
|
||
|
ptr->iHitgroup = ptr->iHitgroup == 2 ? HITGROUP_LEFTARM : ptr->iHitgroup;
|
||
|
ptr->iHitgroup = ptr->iHitgroup == 3 ? HITGROUP_RIGHTARM : ptr->iHitgroup;
|
||
|
}
|
||
|
|
||
|
switch ( ptr->iHitgroup )
|
||
|
{
|
||
|
case HITGROUP_RIGHTARM:
|
||
|
SetBodygroup( ARM_R_GROUP, NO_MEMBRE);
|
||
|
MakeGib ( 2, pevAttacker );
|
||
|
break;
|
||
|
case HITGROUP_LEFTARM:
|
||
|
SetBodygroup( ARM_L_GROUP, NO_MEMBRE);
|
||
|
MakeGib ( 2, pevAttacker );
|
||
|
break;
|
||
|
case HITGROUP_RIGHTLEG:
|
||
|
SetBodygroup( LEG_R_GROUP, NO_MEMBRE);
|
||
|
MakeGib ( 1, pevAttacker );
|
||
|
break;
|
||
|
case HITGROUP_LEFTLEG:
|
||
|
SetBodygroup( LEG_L_GROUP, NO_MEMBRE);
|
||
|
MakeGib ( 1, pevAttacker );
|
||
|
break;
|
||
|
case HITGROUP_HEAD:
|
||
|
SetBodygroup( HEAD_GROUP, NO_HEAD);
|
||
|
MakeGib ( 0, pevAttacker );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void CSniper :: MakeGib ( int body, entvars_t *pevAttacker )
|
||
|
{
|
||
|
|
||
|
if ( m_iHasGibbed == 1 )
|
||
|
return;
|
||
|
m_iHasGibbed = 1;
|
||
|
|
||
|
CGib *pGib = GetClassPtr( (CGib *)NULL );
|
||
|
pGib->Spawn( "models/sniper_gibs.mdl" );
|
||
|
pGib->m_bloodColor = BLOOD_COLOR_RED;
|
||
|
pGib->pev->body = body;
|
||
|
|
||
|
pGib->pev->origin = pev->origin + Vector ( 0, 0, 40 );
|
||
|
pGib->pev->velocity = ( Center() - pevAttacker->origin).Normalize() * 300;
|
||
|
|
||
|
pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 );
|
||
|
pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 );
|
||
|
|
||
|
}
|
||
|
|
||
|
Activity CSniper :: GetDeathActivity ( void )
|
||
|
{
|
||
|
|
||
|
Activity deathActivity = ACT_DIESIMPLE;
|
||
|
|
||
|
if ( pev->deadflag != DEAD_NO )
|
||
|
return m_IdealActivity;
|
||
|
|
||
|
|
||
|
switch ( m_LastHitGroup )
|
||
|
{
|
||
|
case HITGROUP_HEAD:
|
||
|
deathActivity = ACT_DIE_HEADSHOT;
|
||
|
break;
|
||
|
|
||
|
case HITGROUP_STOMACH:
|
||
|
case HITGROUP_CHEST:
|
||
|
case HITGROUP_LEFTLEG:
|
||
|
case HITGROUP_RIGHTLEG:
|
||
|
deathActivity = ACT_DIE_GUTSHOT;
|
||
|
break;
|
||
|
|
||
|
case HITGROUP_LEFTARM:
|
||
|
case HITGROUP_RIGHTARM:
|
||
|
deathActivity = ACT_DIE_BACKSHOT ;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE )
|
||
|
deathActivity = ACT_DIESIMPLE;
|
||
|
|
||
|
return deathActivity;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------
|
||
|
//
|
||
|
// CheckAttacks
|
||
|
//------------------------------------------
|
||
|
|
||
|
|
||
|
BOOL CSniper :: CheckRangeAttack1 ( float flDot, float flDist )
|
||
|
{
|
||
|
if ( flDist <= 4096 )
|
||
|
{
|
||
|
if ( flDist <= 64 )
|
||
|
return FALSE;
|
||
|
|
||
|
TraceResult tr;
|
||
|
Vector vecSrc = GetGunPosition();
|
||
|
Vector vecTarget = m_hEnemy->BodyTarget(vecSrc);
|
||
|
|
||
|
UTIL_TraceLine( vecSrc, vecTarget, ignore_monsters, ignore_glass, ENT(pev), &tr);
|
||
|
|
||
|
if ( tr.flFraction == 1.0 )
|
||
|
return TRUE;
|
||
|
|
||
|
else if ( !FNullEnt ( tr.pHit ) && VARS( tr.pHit )->takedamage == DAMAGE_YES )
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CSniper :: CheckMeleeAttack1 ( float flDot, float flDist )
|
||
|
{
|
||
|
CBaseMonster *pEnemy;
|
||
|
|
||
|
if ( m_hEnemy != NULL )
|
||
|
{
|
||
|
pEnemy = m_hEnemy->MyMonsterPointer();
|
||
|
|
||
|
if ( !pEnemy )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( flDist <= 64 )
|
||
|
return TRUE;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void CSniper :: CheckAmmo ( void )
|
||
|
{
|
||
|
if ( m_cAmmoLoaded <= 0 )
|
||
|
{
|
||
|
SetConditions(bits_COND_NO_AMMO_LOADED);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===============
|
||
|
|
||
|
|
||
|
void CSniper :: HandleAnimEvent( MonsterEvent_t *pEvent )
|
||
|
{
|
||
|
switch (pEvent->event)
|
||
|
{
|
||
|
case SNIPER_AE_SHOOT:
|
||
|
|
||
|
Shoot (); break;
|
||
|
|
||
|
case SNIPER_AE_RELOAD:
|
||
|
|
||
|
m_cAmmoLoaded = SNIPER_MAX_CLIP;
|
||
|
ClearConditions(bits_COND_NO_AMMO_LOADED);
|
||
|
break;
|
||
|
|
||
|
case SNIPER_AE_MELEE_ATTACK1:
|
||
|
{
|
||
|
CBaseEntity *pHurt = Kick();
|
||
|
if ( pHurt )
|
||
|
{
|
||
|
UTIL_MakeVectors( pev->angles );
|
||
|
pHurt->pev->punchangle.z = 25;
|
||
|
pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 200 + gpGlobals->v_up * 100;
|
||
|
pHurt->TakeDamage( pev, pev,25, DMG_CLUB );
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case SNIPER_AE_DROPGUN:
|
||
|
{
|
||
|
SetBodygroup( 2, 1);
|
||
|
|
||
|
Vector vecGunPos = GetGunPosition();
|
||
|
Vector vecGunAngles;
|
||
|
|
||
|
Vector zeroVector(0,0,0);
|
||
|
GetAttachment( 0, zeroVector, vecGunAngles );
|
||
|
DropItem( "weapon_fsniper", vecGunPos, vecGunAngles );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CSniper :: RunTask ( Task_t *pTask )
|
||
|
{
|
||
|
switch ( pTask->iTask )
|
||
|
{
|
||
|
case TASK_RANGE_ATTACK1:
|
||
|
{
|
||
|
if (m_hEnemy != NULL)
|
||
|
{
|
||
|
Vector vecShootDir = m_hEnemy->Center() - Center();
|
||
|
Vector angDir = UTIL_VecToAngles( vecShootDir );
|
||
|
SetBlending( 0, angDir.x );
|
||
|
}
|
||
|
|
||
|
MakeIdealYaw ( m_vecEnemyLKP );
|
||
|
ChangeYaw ( pev->yaw_speed );
|
||
|
|
||
|
CBaseMonster :: RunTask( pTask );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
CBaseMonster :: RunTask( pTask );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------
|
||
|
//
|
||
|
// AI Schedules
|
||
|
//----------------------------------------------------
|
||
|
|
||
|
|
||
|
//-------------------
|
||
|
// Rechargement
|
||
|
|
||
|
Task_t tlSniperRechargement[] =
|
||
|
{
|
||
|
{ TASK_PLAY_SEQUENCE, (float)ACT_RELOAD },
|
||
|
};
|
||
|
|
||
|
Schedule_t slSniperRechargement[] =
|
||
|
{
|
||
|
{
|
||
|
tlSniperRechargement,
|
||
|
ARRAYSIZE ( tlSniperRechargement ),
|
||
|
bits_COND_HEAVY_DAMAGE |
|
||
|
bits_COND_HEAR_SOUND,
|
||
|
|
||
|
0,
|
||
|
"SniperRechargement"
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//-------------------
|
||
|
// abri des grenades
|
||
|
|
||
|
Task_t tlSniperCover[] =
|
||
|
{
|
||
|
{ TASK_PLAY_SEQUENCE, (float)ACT_COWER },
|
||
|
};
|
||
|
|
||
|
Schedule_t slSniperCover[] =
|
||
|
{
|
||
|
{
|
||
|
tlSniperCover,
|
||
|
ARRAYSIZE ( tlSniperRechargement ),
|
||
|
bits_COND_HEAVY_DAMAGE,
|
||
|
|
||
|
0,
|
||
|
"SniperCover"
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
//-------------------
|
||
|
// tir
|
||
|
// red
|
||
|
// ne tire pas sans voir l'ennemi
|
||
|
|
||
|
|
||
|
|
||
|
Task_t tlSniperShoot[] =
|
||
|
{
|
||
|
{ TASK_STOP_MOVING, 0 },
|
||
|
{ TASK_FACE_ENEMY, (float)0 },
|
||
|
{ TASK_RANGE_ATTACK1, (float)0 },
|
||
|
};
|
||
|
|
||
|
Schedule_t slSniperShoot[] =
|
||
|
{
|
||
|
{
|
||
|
tlSniperShoot,
|
||
|
ARRAYSIZE ( tlSniperShoot ),
|
||
|
bits_COND_NEW_ENEMY |
|
||
|
bits_COND_ENEMY_DEAD |
|
||
|
bits_COND_LIGHT_DAMAGE |
|
||
|
bits_COND_HEAVY_DAMAGE |
|
||
|
bits_COND_NO_AMMO_LOADED |
|
||
|
bits_COND_HEAR_SOUND,
|
||
|
|
||
|
bits_SOUND_DANGER,
|
||
|
"SniperShoot"
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
//-------------------
|
||
|
// tableau des AI
|
||
|
|
||
|
DEFINE_CUSTOM_SCHEDULES( CSniper )
|
||
|
{
|
||
|
slSniperRechargement,
|
||
|
slSniperCover,
|
||
|
slSniperShoot,
|
||
|
};
|
||
|
|
||
|
IMPLEMENT_CUSTOM_SCHEDULES( CSniper, CBaseMonster );
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------
|
||
|
//
|
||
|
// Gestion des comportements
|
||
|
//----------------------------------------------------
|
||
|
|
||
|
|
||
|
Schedule_t *CSniper :: GetSchedule( void )
|
||
|
{
|
||
|
switch ( m_MonsterState )
|
||
|
{
|
||
|
|
||
|
if ( HasConditions(bits_COND_HEAR_SOUND) )
|
||
|
{
|
||
|
CSound *pSound = PBestSound();
|
||
|
|
||
|
ASSERT( pSound != NULL );
|
||
|
if ( pSound)
|
||
|
{
|
||
|
if (pSound->m_iType & bits_SOUND_DANGER)
|
||
|
{
|
||
|
return GetScheduleOfType( SCHED_SNIPER_COVER );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( HasConditions( bits_COND_LIGHT_DAMAGE ) )
|
||
|
{
|
||
|
if ( RANDOM_LONG(0,99) <= 75 )
|
||
|
{
|
||
|
ClearConditions( bits_COND_LIGHT_DAMAGE );
|
||
|
return GetScheduleOfType( SCHED_SMALL_FLINCH );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case MONSTERSTATE_COMBAT:
|
||
|
{
|
||
|
if ( HasConditions ( bits_COND_NO_AMMO_LOADED ))
|
||
|
{
|
||
|
return GetScheduleOfType ( SCHED_SNIPER_RECHARGEMENT );
|
||
|
}
|
||
|
|
||
|
if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) )
|
||
|
{
|
||
|
return GetScheduleOfType ( SCHED_MELEE_ATTACK1 );
|
||
|
}
|
||
|
|
||
|
|
||
|
UTIL_MakeVectors ( pev->angles );
|
||
|
Vector2D vec2LOS = ( m_hEnemy->pev->origin - pev->origin ).Make2D();
|
||
|
vec2LOS = vec2LOS.Normalize();
|
||
|
float flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() );
|
||
|
|
||
|
if ( CheckRangeAttack1 ( DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ), (m_hEnemy->pev->origin - pev->origin).Length() ) )
|
||
|
{
|
||
|
return GetScheduleOfType ( SCHED_RANGE_ATTACK1 );
|
||
|
}
|
||
|
|
||
|
} // fin du MS_COMBAT
|
||
|
} // fin du switch
|
||
|
|
||
|
return CBaseMonster :: GetSchedule();
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------
|
||
|
//
|
||
|
// Direction des comportements vers un tableau d'AI
|
||
|
//----------------------------------------------------
|
||
|
|
||
|
|
||
|
Schedule_t* CSniper :: GetScheduleOfType ( int Type )
|
||
|
{
|
||
|
switch ( Type )
|
||
|
{
|
||
|
case SCHED_SNIPER_RECHARGEMENT:
|
||
|
{
|
||
|
return &slSniperRechargement[ 0 ];
|
||
|
}
|
||
|
case SCHED_SNIPER_COVER:
|
||
|
{
|
||
|
return &slSniperCover[ 0 ];
|
||
|
}
|
||
|
case SCHED_RANGE_ATTACK1:
|
||
|
{
|
||
|
return &slSniperShoot[ 0 ];
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
return CBaseMonster :: GetScheduleOfType ( Type );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|