/****************************************************************************
* *
* Tank . cpp par Julien *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "extdll.h"
# include "util.h"
# include "cbase.h"
# include "monsters.h"
# include "weapons.h"
# include "soundent.h"
# include "effects.h"
# include "player.h"
# include "explode.h"
# include "func_break.h"
//========================================
// Fonctions externes
//========================================
extern void EnvSmokeCreate ( const Vector & center , int m_iScale , float m_fFrameRate , int m_iTime , int m_iEndTime ) ;
extern int gmsgTankView ;
//=========================================
// Variables
//=========================================
# define NEXTTHINK_TIME 0.1
# define BSP_NEXTTHINK_TIME 0.05
# define TANK_TOURELLE_ROT_SPEED 12
# define TANK_ROT_SPEED 50
# define TANK_REFIRE_DELAY 1.5
# define SPRITE_SMOKE ("sprites / muzzleflash.spr")
# define SPRITE_SMOKE_SCALE 1.5
# define SPRITE_MUZ ("sprites / muzzleflash1.spr")
# define SPRITE_MUZ_SCALE 1
# define SPRITE_FEU ("sprites / lflammes02.spr")
# define SPRITE_FEU_SCALE 1
# define SPRITE_SMOKEBALL ("sprites / tank_smokeball.spr")
# define SPRITE_SMOKEBALL_SCALE 2
# define MITRAILLEUSE_SOUND "tank / mitrailleuse.wav"
# define TIR_SOUND "tank / tir.wav"
# define TANK_SOUND "ambience / truck2.wav"
# define CHENILLES_SOUND "tank / chenilles.wav"
# define CHOC_SOUND "debris / metal3.wav"
# define ACCELERE_SOUND1 "tank / accelere1.wav"
# define ACCELERE_SOUND2 "tank / accelere2.wav"
# define ACCELERE_SOUND3 "tank / accelere3.wav"
# define DECCELERE_SOUND "tank / deccelere1.wav"
# define TANK_EXPLO_SOUND1 "tank / explode.wav"
# define TANK_EXPLO_SOUND2 "weapons / mortarhit.wav"
# define TOURELLE_MAX_ROT_X 25
# define TOURELLE_MAX_ROT_X2 -10
# define TOURELLE_MAX_ROT_Y 120
# define TANK_SPEED 200
# define TANK_ACCELERATION 5
# define TANK_DECCELERATION 30
# define CAM_DIST_UP 100
# define CAM_DIST_BACK 300
//distances pour l' UTIL_TraceLine ()
# define NEW_ORIGIN ( pev->origin + vecNewVelocity / 10 + gpGlobals->v_up * 2 )
# define DIST_TOP 60
# define DIST_FRONT 140
# define DIST_FRONT_UP 185
# define DIST_BACK -150
# define DIST_BACK_UP -170
# define DIST_SIDE 105
# define MOVE_FORWARD (1<<0)
# define MOVE_BACKWARD (1<<1)
# define PUSH_FORWARD (1<<2)
# define PUSH_BACKWARD (1<<3)
# define TANK_LIFE 1200
# define TANK_RECHARGE 15 // charge du tank_charger par 10e de seconde
//=================================
// classes
//=================================
class CTank ;
class CTankCam : public CPointEntity
{
public :
void Spawn ( void ) ;
void Precache ( void ) ;
void EXPORT CamThink ( void ) ;
void SetPlayerTankView ( BOOL setOn ) ;
virtual int ObjectCaps ( void ) { return FCAP_ACROSS_TRANSITION ; } ; // traverse les changelevels
CTank * m_pTankModel ;
float m_skin ;
Vector m_vecTourelleAngle ;
float m_flNextFrameTime ;
int Save ( CSave & save ) ;
int Restore ( CRestore & restore ) ;
static TYPEDESCRIPTION m_SaveData [ ] ;
} ;
LINK_ENTITY_TO_CLASS ( info_tank_camera , CTankCam ) ;
TYPEDESCRIPTION CTankCam : : m_SaveData [ ] =
{
DEFINE_FIELD ( CTankCam , m_pTankModel , FIELD_CLASSPTR ) ,
DEFINE_FIELD ( CTankCam , m_skin , FIELD_FLOAT ) ,
DEFINE_FIELD ( CTankCam , m_vecTourelleAngle , FIELD_VECTOR ) ,
DEFINE_FIELD ( CTankCam , m_flNextFrameTime , FIELD_TIME ) ,
} ;
IMPLEMENT_SAVERESTORE ( CTankCam , CPointEntity ) ;
class CTankBSP : public CBaseEntity /*Monster*/
{
public :
void Spawn ( void ) ;
void Precache ( void ) ;
int BloodColor ( void ) { return DONT_BLEED ; } ;
int Classify ( void ) ;
int ObjectCaps ( void ) { return CBaseEntity : : ObjectCaps ( ) & ~ FCAP_ACROSS_TRANSITION ; }
void Blocked ( CBaseEntity * pOther ) ;
void TraceAttack ( entvars_t * pevAttacker , float flDamage , Vector vecDir , TraceResult * ptr , int bitsDamageType ) ;
int TakeDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int bitsDamageType ) ;
void EXPORT TankThink ( void ) ;
void EXPORT TouchPlayer ( CBaseEntity * pOther ) ;
CTank * m_pTankModel ;
int Save ( CSave & save ) ;
int Restore ( CRestore & restore ) ;
static TYPEDESCRIPTION m_SaveData [ ] ;
} ;
LINK_ENTITY_TO_CLASS ( vehicle_tank , CTankBSP ) ;
TYPEDESCRIPTION CTankBSP : : m_SaveData [ ] =
{
DEFINE_FIELD ( CTankBSP , m_pTankModel , FIELD_CLASSPTR ) ,
} ;
IMPLEMENT_SAVERESTORE ( CTankBSP , CBaseEntity ) ;
class CTank : public CBaseMonster
{
public :
void Spawn ( void ) ;
void Precache ( void ) ;
int Classify ( void ) { return CLASS_NONE ; }
int BloodColor ( void ) { return DONT_BLEED ; }
void EXPORT UseTank ( CBaseEntity * pActivator , CBaseEntity * pCaller , USE_TYPE useType , float value ) ;
void EXPORT IdleThink ( void ) ;
void EXPORT DriveThink ( void ) ;
void EXPORT StopThink ( void ) ;
void EXPORT DeadThink ( void ) ;
void TraceAttack ( entvars_t * pevAttacker , float flDamage , Vector vecDir , TraceResult * ptr , int bitsDamageType ) ;
int TakeDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int bitsDamageType ) ;
void TankDeath ( void ) ;
void Fire ( int canon ) ;
void UpdateSound ( void ) ;
int ModifAngles ( int angle ) ;
void UpdateCamAngle ( Vector vecNewPosition , float flTime ) ;
Vector UpdateCam ( void ) ;
Vector TourelleAngle ( void ) ;
CTankCam * m_pCam ;
CBasePlayer * m_pPlayer ;
CTankBSP * m_pTankBSP ;
int bTankOn ;
int bSetView ;
int bTankDead ;
float m_flLastAttack1 ;
float m_flNextSound ;
int bCanon ;
int m_soundPlaying ;
int m_iTankmove ;
Vector m_PlayerAngles ;
Vector vecCamOrigin ( void ) { Vector origin = pev - > origin ; origin . z + = 150 ; return origin ; } ;
Vector vecCamAim ;
Vector vecCamTarget ;
float m_flTempHealth ;
int Save ( CSave & save ) ;
int Restore ( CRestore & restore ) ;
static TYPEDESCRIPTION m_SaveData [ ] ;
private :
unsigned short m_usAdjustPitch ;
} ;
LINK_ENTITY_TO_CLASS ( info_tank_model , CTank ) ;
TYPEDESCRIPTION CTank : : m_SaveData [ ] =
{
DEFINE_FIELD ( CTank , m_pCam , FIELD_CLASSPTR ) ,
DEFINE_FIELD ( CTank , m_pPlayer , FIELD_CLASSPTR ) ,
DEFINE_FIELD ( CTank , m_pTankBSP , FIELD_CLASSPTR ) ,
DEFINE_FIELD ( CTank , bTankOn , FIELD_INTEGER ) ,
DEFINE_FIELD ( CTank , bSetView , FIELD_INTEGER ) ,
DEFINE_FIELD ( CTank , bTankDead , FIELD_INTEGER ) ,
DEFINE_FIELD ( CTank , m_iTankmove , FIELD_INTEGER ) ,
DEFINE_FIELD ( CTank , m_flLastAttack1 , FIELD_TIME ) ,
DEFINE_FIELD ( CTank , m_flNextSound , FIELD_TIME ) ,
DEFINE_FIELD ( CTank , bCanon , FIELD_INTEGER ) ,
DEFINE_FIELD ( CTank , m_flTempHealth , FIELD_FLOAT ) ,
DEFINE_FIELD ( CTank , m_PlayerAngles , FIELD_VECTOR ) ,
DEFINE_FIELD ( CTank , vecCamAim , FIELD_POSITION_VECTOR ) ,
DEFINE_FIELD ( CTank , vecCamTarget , FIELD_POSITION_VECTOR ) ,
} ;
//IMPLEMENT_SAVERESTORE( CTank, CBaseMonster );
//===================================
// fonctions
//===================================
//=================================
// TankCam
//
void CTankCam : : Precache ( void )
{
PRECACHE_MODEL ( " models/tank_cam.mdl " ) ;
}
void CTankCam : : Spawn ( void )
{
Precache ( ) ;
SET_MODEL ( ENT ( pev ) , " models/tank_cam.mdl " ) ;
Vector zeroVector ( 0 , 0 , 0 ) ;
Vector zeroVector1 ( 0 , 0 , 0 ) ;
UTIL_SetSize ( pev , zeroVector , zeroVector1 ) ;
UTIL_SetOrigin ( pev , pev - > origin ) ;
pev - > movetype = MOVETYPE_NOCLIP ;
pev - > solid = SOLID_NOT ;
pev - > classname = MAKE_STRING ( " info_tank_camera " ) ; //necessaire pour le passage a la sauvegarde : getclassptr ne cree pas de pev->classname et donc l entite n est pas prise en compte
pev - > takedamage = DAMAGE_NO ;
SetThink ( & CTankCam : : CamThink ) ;
pev - > nextthink = gpGlobals - > time + 1.5 ;
}
void CTankCam : : CamThink ( void )
{
pev - > nextthink = gpGlobals - > time + BSP_NEXTTHINK_TIME ;
// fonction appel
// le skin des chenilles a besoin d un taux de rafraichissement eleve pour etre realiste
// skin des chenilles
// nombre d images : 9
if ( m_pTankModel = = NULL )
return ;
m_skin + = m_pTankModel - > pev - > velocity . Length ( ) / 20 ;
if ( ( int ) m_skin ! = m_pTankModel - > pev - > skin )
{
while ( ( int ) m_skin > 8 ) //de 0
{
m_skin - = 8 ;
}
m_pTankModel - > pev - > skin = ( int ) m_skin ;
}
if ( gpGlobals - > time < m_flNextFrameTime )
{
float flDifY = m_pTankModel - > pev - > v_angle . y - m_vecTourelleAngle . y ;
float flDifX = m_pTankModel - > pev - > v_angle . x - m_vecTourelleAngle . x ;
float flNewAngleY = ( ( gpGlobals - > time - ( m_flNextFrameTime - NEXTTHINK_TIME ) ) * flDifY ) / NEXTTHINK_TIME ;
float flNewAngleX = ( ( gpGlobals - > time - ( m_flNextFrameTime - NEXTTHINK_TIME ) ) * flDifX ) / NEXTTHINK_TIME ;
m_pTankModel - > SetBoneController ( 1 , m_vecTourelleAngle . y + flNewAngleY ) ;
m_pTankModel - > SetBoneController ( 0 , m_vecTourelleAngle . x + flNewAngleX ) ;
}
// if ( m_pTankModel->bSetView == TRUE )
// SetPlayerTankView(TRUE); // rafraichissement de la positon de la camera pour le client
if ( m_pTankModel - > bTankOn = = TRUE )
SetPlayerTankView ( TRUE ) ; // rafraichissement de la positon de la camera pour le client
}
void CTankCam : : SetPlayerTankView ( BOOL setOn )
{
// bug des dommages
m_pTankModel - > m_flTempHealth = m_pTankModel - > m_pTankBSP - > pev - > health ;
// message client
MESSAGE_BEGIN ( MSG_ONE , gmsgTankView , NULL , m_pTankModel - > m_pPlayer - > pev ) ;
WRITE_BYTE ( setOn = = TRUE ) ;
WRITE_COORD ( ENTINDEX ( edict ( ) ) ) ;
WRITE_LONG ( m_pTankModel - > m_pTankBSP - > pev - > health ) ;
MESSAGE_END ( ) ;
}
//==================================
// TankBSP
void CTankBSP : : Precache ( void )
{
UTIL_PrecacheOther ( " info_tank_model " ) ;
}
void CTankBSP : : Spawn ( void )
{
Precache ( ) ;
pev - > solid = SOLID_BSP ;
pev - > movetype = MOVETYPE_PUSH ;
SET_MODEL ( ENT ( pev ) , STRING ( pev - > model ) ) ;
UTIL_SetSize ( pev , pev - > mins , pev - > maxs ) ;
UTIL_SetOrigin ( pev , pev - > origin ) ;
pev - > flags | = FL_MONSTER ;
pev - > takedamage = DAMAGE_YES ;
pev - > rendermode = kRenderTransTexture ;
pev - > renderamt = 0 ;
pev - > view_ofs = Vector ( 0 , 0 , 100 ) ;
pev - > health = TANK_LIFE ;
m_pTankModel = GetClassPtr ( ( CTank * ) NULL ) ;
UTIL_SetOrigin ( m_pTankModel - > pev , pev - > origin ) ;
m_pTankModel - > pev - > angles = pev - > angles ;
m_pTankModel - > m_pTankBSP = this ;
m_pTankModel - > Spawn ( ) ;
SetThink ( & CTankBSP : : TankThink ) ;
SetTouch ( & CTankBSP : : TouchPlayer ) ;
pev - > nextthink = pev - > ltime + 0xFF ;
}
int CTankBSP : : Classify ( void )
{
// trouve le model
edict_t * pent = FIND_ENTITY_BY_CLASSNAME ( NULL , " info_tank_model " ) ;
if ( pent = = NULL )
return CLASS_NONE ;
CTank * pTank = ( CTank * ) CBaseEntity : : Instance ( pent ) ;
// classe selon l'
if ( pTank - > bTankOn = = 1 )
return CLASS_PLAYER_ALLY ;
return CLASS_NONE ;
} ;
void CTankBSP : : TankThink ( void )
{
//ne sert strictement
pev - > nextthink = pev - > ltime + 0xFF ;
}
void CTankBSP : : Blocked ( CBaseEntity * pOther )
{
pOther - > TakeDamage ( pev , pev , 0xFF , DMG_CRUSH ) ;
}
void CTankBSP : : TraceAttack ( entvars_t * pevAttacker , float flDamage , Vector vecDir , TraceResult * ptr , int bitsDamageType )
{
CBaseEntity : : TraceAttack ( pevAttacker , flDamage , vecDir , ptr , bitsDamageType ) ;
}
int CTankBSP : : TakeDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int bitsDamageType )
{
m_pTankModel - > m_flTempHealth = pev - > health ;
if ( m_pTankModel - > bTankOn = = FALSE )
return 1 ;
// le joueur ne le blesse pas - debug
if ( FClassnameIs ( pevInflictor , " player " ) )
return 1 ;
// que des d
if ( ! ( bitsDamageType & DMG_BLAST ) )
return 1 ;
// ne se blesse pas lui meme
if ( pevInflictor = = m_pTankModel - > pev )
return 1 ;
// d
if ( pev - > health = = 0 )
return 1 ;
// mine antichar
if ( FClassnameIs ( pevInflictor , " monster_mine_ac " ) | | FClassnameIs ( pevAttacker , " monster_mine_ac " ) )
pev - > health = 0 ;
pev - > health - = flDamage ;
// pas quand le tank est eteint
if ( m_pTankModel - > m_pCam ! = NULL )
{
m_pTankModel - > m_pCam - > SetPlayerTankView ( TRUE ) ; // rafraichissement de la vie c
if ( pev - > health < = 0 )
{
pev - > health = 0 ;
m_pTankModel - > TankDeath ( ) ;
return 0 ;
}
}
return 1 ;
}
void CTankBSP : : TouchPlayer ( CBaseEntity * pOther )
{
if ( ! pOther - > IsPlayer ( ) )
return ;
// le joueur n active le tank que s il le touche et qu il est a peu pres au meme niveau que le tank pour eviter que le joueur sortant sur le toit du tank ne l active a nouveau
if ( pOther - > pev - > origin . z > pev - > origin . z + 48 )
return ;
// m_pTankModel->UseTank( pOther, pOther, USE_TOGGLE, 0 );
edict_t * pent = FIND_ENTITY_BY_CLASSNAME ( NULL , " info_tank_model " ) ;
if ( pent = = NULL )
return ;
CTank * pTank = ( CTank * ) CBaseEntity : : Instance ( pent ) ;
pTank - > UseTank ( pOther , pOther , USE_TOGGLE , 0 ) ;
}
//==================================
// CTank
//
void CTank : : Spawn ( void )
{
Precache ( ) ;
// pev->movetype = MOVETYPE_NOCLIP;
pev - > movetype = MOVETYPE_FLY ;
pev - > solid = SOLID_BBOX ;
pev - > classname = MAKE_STRING ( " info_tank_model " ) ; //necessaire pour le passage a la sauvegarde : getclassptr ne cree pas de pev->classname et donc l entite n est pas prise en compte
SET_MODEL ( ENT ( pev ) , " models/tank.mdl " ) ;
Vector zeroVector ( 0 , 0 , 0 ) ;
Vector zeroVector1 ( 0 , 0 , 0 ) ;
UTIL_SetSize ( pev , zeroVector , zeroVector1 ) ;
UTIL_SetOrigin ( pev , pev - > origin ) ;
pev - > flags | = FL_MONSTER ;
pev - > takedamage = DAMAGE_NO ;
pev - > sequence = 0 ;
pev - > health = 100 ;
m_flTempHealth = m_pTankBSP - > pev - > health ;
ResetSequenceInfo ( ) ;
pev - > frame = RANDOM_LONG ( 0 , 0xFF ) ;
InitBoneControllers ( ) ;
bTankOn = bSetView = bTankDead = 0 ;
m_flLastAttack1 = m_soundPlaying = 0 ;
SetThink ( & CTank : : IdleThink ) ;
pev - > nextthink = gpGlobals - > time + 1 ;
}
void CTank : : Precache ( void )
{
UTIL_PrecacheOther ( " info_tank_camera " ) ;
PRECACHE_MODEL ( " models/tank.mdl " ) ;
PRECACHE_MODEL ( ( char * ) SPRITE_SMOKE ) ;
PRECACHE_MODEL ( ( char * ) SPRITE_MUZ ) ;
PRECACHE_MODEL ( ( char * ) SPRITE_SMOKEBALL ) ;
PRECACHE_MODEL ( ( char * ) SPRITE_FEU ) ;
PRECACHE_MODEL ( " models/mechgibs.mdl " ) ;
PRECACHE_SOUND ( MITRAILLEUSE_SOUND ) ;
PRECACHE_SOUND ( TIR_SOUND ) ;
PRECACHE_SOUND ( TANK_SOUND ) ;
PRECACHE_SOUND ( CHOC_SOUND ) ;
PRECACHE_SOUND ( CHENILLES_SOUND ) ;
PRECACHE_SOUND ( ACCELERE_SOUND1 ) ;
PRECACHE_SOUND ( ACCELERE_SOUND2 ) ;
PRECACHE_SOUND ( ACCELERE_SOUND3 ) ;
PRECACHE_SOUND ( DECCELERE_SOUND ) ;
PRECACHE_SOUND ( TANK_EXPLO_SOUND1 ) ;
PRECACHE_SOUND ( TANK_EXPLO_SOUND2 ) ;
m_usAdjustPitch = PRECACHE_EVENT ( 1 , " events/train.sc " ) ;
}
void CTank : : TraceAttack ( entvars_t * pevAttacker , float flDamage , Vector vecDir , TraceResult * ptr , int bitsDamageType )
{
}
int CTank : : TakeDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int bitsDamageType )
{
return 0 ;
}
void CTank : : UseTank ( CBaseEntity * pActivator , CBaseEntity * pCaller , USE_TYPE useType , float value )
{
edict_t * pentFind ;
CBaseEntity * pFind ;
pentFind = FIND_ENTITY_BY_CLASSNAME ( NULL , " info_teleport_destination " ) ;
if ( pentFind = = NULL )
{
ALERT ( at_console , " info_tank_model : pas de teleport destination !!! \n " ) ;
return ;
}
else
{
pFind = CBaseEntity : : Instance ( pentFind ) ;
Vector vecTeleport = pFind - > pev - > origin ;
UTIL_SetOrigin ( pActivator - > pev , vecTeleport ) ;
m_pPlayer = ( CBasePlayer * ) pActivator ;
m_pPlayer - > m_iDrivingTank = TRUE ;
m_pPlayer - > m_iHideHUD | = HIDEHUD_ALL ;
m_pCam = GetClassPtr ( ( CTankCam * ) NULL ) ;
UTIL_SetOrigin ( m_pCam - > pev , vecCamOrigin ( ) ) ;
m_pCam - > pev - > angles = TourelleAngle ( ) ;
m_pCam - > Spawn ( ) ;
m_pCam - > pev - > velocity = ( UpdateCam ( ) - vecCamOrigin ( ) ) / 2 ;
m_pCam - > m_pTankModel = this ;
UpdateCamAngle ( UpdateCam ( ) , 2 ) ;
m_pCam - > SetPlayerTankView ( TRUE ) ;
SetThink ( & CTank : : DriveThink ) ;
pev - > nextthink = gpGlobals - > time + 2 ;
}
}
//===============================================================
//===============================================================
// Fonctions Think
void CTank : : IdleThink ( void )
{
UpdateSound ( ) ;
pev - > nextthink = gpGlobals - > time + 0.1 ;
}
//============================================
// Le bone controller 0 correspond au d
// il
// le bone 1 est le d
// et l axe y du joueur
void CTank : : DriveThink ( void )
{
pev - > nextthink = gpGlobals - > time + NEXTTHINK_TIME ;
StudioFrameAdvance ( ) ;
if ( pev - > sequence = = 1 )
pev - > sequence = 0 ;
// ALERT ( at_console, "playerdrivetank : %s\n", m_pPlayer->m_iDrivingTank == TRUE ? "TRUE" : "FALSE" );
// apres le changement de niveau, reinitialisation de la vue
if ( bSetView = = 1 )
{
// actualisation de la vie du bsp
m_pTankBSP - > pev - > health = m_flTempHealth ;
// r
m_pCam - > SetPlayerTankView ( TRUE ) ;
bSetView = 0 ;
}
//quitte le tank
if ( m_pPlayer - > pev - > button & IN_USE )
{
pev - > velocity = pev - > avelocity = m_pTankBSP - > pev - > velocity = m_pTankBSP - > pev - > avelocity = Vector ( 0 , 0 , 0 ) ;
m_pTankBSP - > pev - > origin = pev - > origin ;
m_pTankBSP - > pev - > angles = pev - > angles ;
m_pCam - > pev - > velocity = ( vecCamOrigin ( ) - m_pCam - > pev - > origin ) / 2 ;
UpdateCamAngle ( m_pCam - > pev - > origin , 2 ) ;
UpdateSound ( ) ;
SetThink ( & CTank : : StopThink ) ;
pev - > nextthink = gpGlobals - > time + 2 ;
return ;
}
float flNextVAngleY = pev - > v_angle . y ;
float flNextVAngleX = pev - > v_angle . x ;
float flNewAVelocity ;
Vector vecNewVelocity ;
//---------------------------------------------_-_-_ _ _
//modifications de la direction de la tourelle
if ( bTankOn = = 0 )
{
bTankOn = 1 ;
m_PlayerAngles . x = m_pPlayer - > pev - > angles . x ;
m_PlayerAngles . y = m_pPlayer - > pev - > angles . y ;
}
if ( m_pPlayer - > pev - > angles . y ! = m_PlayerAngles . y )
{
int iSens ;
int iDist = ModifAngles ( m_pPlayer - > pev - > angles . y ) - ModifAngles ( m_PlayerAngles . y ) ;
if ( fabs ( iDist ) > 180 )
{
if ( iDist > 0 )
iDist = iDist - 360 ;
else
iDist = iDist + 360 ;
}
iSens = iDist = = fabs ( iDist ) ? 1 : - 1 ;
iDist = fabs ( iDist ) ;
if ( iDist < TANK_TOURELLE_ROT_SPEED )
flNextVAngleY + = iDist * iSens ;
else
flNextVAngleY + = TANK_TOURELLE_ROT_SPEED * iSens ;
if ( flNextVAngleY > TOURELLE_MAX_ROT_Y )
flNextVAngleY = TOURELLE_MAX_ROT_Y ;
if ( flNextVAngleY < - TOURELLE_MAX_ROT_Y )
flNextVAngleY = - TOURELLE_MAX_ROT_Y ;
}
if ( m_pPlayer - > pev - > angles . x ! = m_PlayerAngles . x )
{
int iSens ;
int iDist = ModifAngles ( m_pPlayer - > pev - > angles . x ) - ModifAngles ( m_PlayerAngles . x ) ;
if ( fabs ( iDist ) > 180 )
{
if ( iDist > 0 )
iDist = iDist - 360 ;
else
iDist = iDist + 360 ;
}
iSens = iDist = = fabs ( iDist ) ? 1 : - 1 ;
iDist = fabs ( iDist ) ;
if ( iDist < TANK_TOURELLE_ROT_SPEED )
flNextVAngleX + = iDist * iSens ;
else
flNextVAngleX + = TANK_TOURELLE_ROT_SPEED * iSens ;
if ( flNextVAngleX > TOURELLE_MAX_ROT_X )
flNextVAngleX = TOURELLE_MAX_ROT_X ;
if ( flNextVAngleX < TOURELLE_MAX_ROT_X2 )
flNextVAngleX = TOURELLE_MAX_ROT_X2 ;
}
m_PlayerAngles . y = m_pPlayer - > pev - > angles . y ;
m_PlayerAngles . x = m_pPlayer - > pev - > angles . x ;
//---------------------------------
// sons d'acceleration du tank
float flSpeed = pev - > velocity . Length ( ) ;
if ( m_flNextSound < gpGlobals - > time )
{
if ( ( m_pPlayer - > pev - > button & IN_FORWARD ) & & ( ( flSpeed = = 0 ) | | ( m_iTankmove & MOVE_BACKWARD ) ) )
{
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_ITEM , ACCELERE_SOUND1 , 1 , ATTN_NONE , 0 , 100 ) ;
m_flNextSound = gpGlobals - > time + 2.5 ;
}
else if ( ( m_pPlayer - > pev - > button & IN_BACK ) & & ( m_iTankmove & MOVE_FORWARD ) )
{
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_ITEM , DECCELERE_SOUND , 1 , ATTN_NONE , 0 , 100 ) ;
m_flNextSound = gpGlobals - > time + 2.5 ;
}
else if ( ( m_pPlayer - > pev - > button & IN_FORWARD ) & & ( m_iTankmove & MOVE_FORWARD ) & & ! ( m_iTankmove & PUSH_FORWARD ) )
{
if ( RANDOM_LONG ( 0 , 1 ) )
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_ITEM , ACCELERE_SOUND2 , 1 , ATTN_NONE , 0 , 100 ) ;
else
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_ITEM , ACCELERE_SOUND3 , 1 , ATTN_NONE , 0 , 100 ) ;
m_flNextSound = gpGlobals - > time + 2.5 ;
}
}
//-------------------------------
//modification de la vitesse du tank
UTIL_MakeVectors ( pev - > angles ) ;
int iSens = UTIL_AngleDiff ( UTIL_VecToAngles ( pev - > velocity ) . y , UTIL_VecToAngles ( gpGlobals - > v_forward ) . y ) ;
if ( flSpeed = = 0 )
iSens = 0 ;
else if ( iSens < - 45 | | iSens > 45 )
iSens = - 1 ;
else
iSens = 1 ;
if ( m_pPlayer - > pev - > button & IN_FORWARD )
{
m_iTankmove | = PUSH_FORWARD ;
m_iTankmove & = ~ PUSH_BACKWARD ;
if ( iSens = = - 1 )
{
if ( flSpeed > TANK_DECCELERATION * 2 )
vecNewVelocity = gpGlobals - > v_forward * - ( flSpeed - TANK_DECCELERATION ) ;
else
vecNewVelocity = Vector ( 0 , 0 , 0 ) ;
}
else if ( flSpeed < 250 )
vecNewVelocity = gpGlobals - > v_forward * ( flSpeed + TANK_ACCELERATION ) ;
else
vecNewVelocity = gpGlobals - > v_forward * 250 ;
}
else if ( m_pPlayer - > pev - > button & IN_BACK )
{
m_iTankmove | = PUSH_BACKWARD ;
m_iTankmove & = ~ PUSH_FORWARD ;
if ( iSens = = 1 )
{
if ( flSpeed > TANK_DECCELERATION * 2 )
vecNewVelocity = gpGlobals - > v_forward * ( flSpeed - TANK_DECCELERATION ) ;
else
vecNewVelocity = Vector ( 0 , 0 , 0 ) ;
}
else if ( flSpeed < 150 )
vecNewVelocity = gpGlobals - > v_forward * - ( flSpeed + TANK_ACCELERATION ) ;
else
vecNewVelocity = gpGlobals - > v_forward * - 150 ;
}
else
{
if ( flSpeed > 5 )
vecNewVelocity = gpGlobals - > v_forward * ( flSpeed - 1 ) * iSens ;
else
vecNewVelocity = gpGlobals - > v_forward * flSpeed * iSens ;
m_iTankmove & = ~ PUSH_BACKWARD ;
m_iTankmove & = ~ PUSH_FORWARD ;
}
if ( iSens = = 1 )
{
m_iTankmove | = MOVE_FORWARD ;
m_iTankmove & = ~ MOVE_BACKWARD ;
}
else
{
m_iTankmove | = MOVE_BACKWARD ;
m_iTankmove & = ~ MOVE_FORWARD ;
}
//modification de la direction du tank
if ( m_pPlayer - > pev - > button & IN_MOVELEFT )
flNewAVelocity = TANK_ROT_SPEED ;
else if ( m_pPlayer - > pev - > button & IN_MOVERIGHT )
flNewAVelocity = - TANK_ROT_SPEED ;
else
flNewAVelocity = 0 ;
// test de la position envisag
UTIL_MakeVectors ( pev - > angles + Vector ( 0 , flNewAVelocity / 10 , 0 ) ) ;
TraceResult tr [ 4 ] /*1,tr2,tr3,tr4*/ ;
Vector vecFrontLeft , vecFrontRight , vecBackLeft , vecBackRight ;
vecFrontLeft = NEW_ORIGIN + gpGlobals - > v_forward * DIST_FRONT_UP + gpGlobals - > v_right * - DIST_SIDE + gpGlobals - > v_up * DIST_TOP ;
vecFrontRight = NEW_ORIGIN + gpGlobals - > v_forward * DIST_FRONT_UP + gpGlobals - > v_right * DIST_SIDE + gpGlobals - > v_up * DIST_TOP ;
vecBackLeft = NEW_ORIGIN + gpGlobals - > v_forward * DIST_BACK_UP + gpGlobals - > v_right * - DIST_SIDE + gpGlobals - > v_up * DIST_TOP ;
vecBackRight = NEW_ORIGIN + gpGlobals - > v_forward * DIST_BACK_UP + gpGlobals - > v_right * DIST_SIDE + gpGlobals - > v_up * DIST_TOP ;
UTIL_TraceLine ( vecFrontLeft , vecFrontRight , ignore_monsters , ENT ( m_pTankBSP - > pev ) , & tr [ 0 ] ) ;
UTIL_TraceLine ( vecFrontRight , vecBackRight , ignore_monsters , ENT ( m_pTankBSP - > pev ) , & tr [ 1 ] ) ;
UTIL_TraceLine ( vecBackRight , vecBackLeft , ignore_monsters , ENT ( m_pTankBSP - > pev ) , & tr [ 2 ] ) ;
UTIL_TraceLine ( vecBackLeft , vecFrontLeft , ignore_monsters , ENT ( m_pTankBSP - > pev ) , & tr [ 3 ] ) ;
//pas de collision - application de la nouvelle position
if ( tr [ 0 ] . vecEndPos = = vecFrontRight & & tr [ 1 ] . vecEndPos = = vecBackRight & & tr [ 2 ] . vecEndPos = = vecBackLeft & & tr [ 3 ] . vecEndPos = = vecFrontLeft )
{
StudioFrameAdvance ( 0.1 ) ;
pev - > velocity = vecNewVelocity ;
pev - > avelocity = Vector ( 0 , flNewAVelocity , 0 ) ;
m_pCam - > m_vecTourelleAngle = pev - > v_angle ;
m_pCam - > m_flNextFrameTime = pev - > nextthink ;
pev - > v_angle . y = flNextVAngleY ;
pev - > v_angle . x = flNextVAngleX ;
m_pTankBSP - > pev - > velocity = ( ( pev - > origin + vecNewVelocity * 10 ) - m_pTankBSP - > pev - > origin ) / 10 ;
m_pTankBSP - > pev - > avelocity = ( ( pev - > angles + Vector ( 0 , flNewAVelocity * 10 , 0 ) - m_pTankBSP - > pev - > angles ) ) / 10 ;
// pour combler la diff
}
//collision - arret du tank
else
{
pev - > velocity = pev - > avelocity = Vector ( 0 , 0 , 0 ) ;
m_pTankBSP - > pev - > velocity = ( pev - > origin - m_pTankBSP - > pev - > origin ) / 10 ;
m_pTankBSP - > pev - > avelocity = ( pev - > angles - m_pTankBSP - > pev - > angles ) / 10 ;
if ( flSpeed > 50 ) // choc violent
{
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_VOICE , CHOC_SOUND , 0.9 , ATTN_NORM , 0 , 60 ) ;
}
}
// application des dommages
vecFrontLeft = vecFrontLeft + Vector ( 0 , 0 , 10 - DIST_TOP ) ;
vecFrontRight = vecFrontRight + Vector ( 0 , 0 , 10 - DIST_TOP ) ;
vecBackRight = vecBackRight + Vector ( 0 , 0 , 10 - DIST_TOP ) ;
vecBackLeft = vecBackLeft + Vector ( 0 , 0 , 10 - DIST_TOP ) ;
UTIL_TraceLine ( vecFrontLeft , vecFrontRight , dont_ignore_monsters , ENT ( m_pTankBSP - > pev ) , & tr [ 0 ] ) ;
UTIL_TraceLine ( vecFrontRight , vecBackRight , dont_ignore_monsters , ENT ( m_pTankBSP - > pev ) , & tr [ 1 ] ) ;
UTIL_TraceLine ( vecBackRight , vecBackLeft , dont_ignore_monsters , ENT ( m_pTankBSP - > pev ) , & tr [ 2 ] ) ;
UTIL_TraceLine ( vecBackLeft , vecFrontLeft , dont_ignore_monsters , ENT ( m_pTankBSP - > pev ) , & tr [ 3 ] ) ;
CBaseEntity * pEntity = NULL ;
for ( int i = 0 ; i < 4 ; i + + )
{
if ( tr [ i ] . pHit ! = NULL )
{
pEntity = CBaseEntity : : Instance ( tr [ i ] . pHit ) ;
if ( pEntity ! = NULL & & pEntity - > pev - > takedamage )
{
float fDamage ;
if ( FClassnameIs ( tr [ i ] . pHit , " func_breakable " ) )
{
fDamage = pEntity - > pev - > health ;
}
else
{
fDamage = pev - > velocity . Length ( ) * 1.5 + 20 ;
}
pEntity - > TakeDamage ( pev , pev , fDamage , DMG_CRUSH ) ;
}
}
}
//rectification de la position de la camera
vecCamAim = UpdateCam ( ) ;
if ( m_pCam - > pev - > origin ! = vecCamAim )
m_pCam - > pev - > velocity = ( vecCamAim - m_pCam - > pev - > origin ) * 10 ;
UpdateCamAngle ( vecCamAim , NEXTTHINK_TIME ) ;
//tir de la tourelle
if ( ( m_pPlayer - > pev - > button & IN_ATTACK ) & & ( gpGlobals - > time > m_flLastAttack1 + TANK_REFIRE_DELAY ) )
{
Fire ( bCanon ) ;
bCanon = bCanon = = TRUE ? FALSE : TRUE ;
EMIT_SOUND ( ENT ( pev ) , CHAN_AUTO , TIR_SOUND , 1 , ATTN_NORM ) ;
m_flLastAttack1 = gpGlobals - > time ;
m_pCam - > pev - > avelocity . x - = 45 ;
}
//tir de la mitrailleuse
if ( m_pPlayer - > pev - > button & IN_ATTACK2 )
{
Vector posGun , dirGun ;
Vector zeroVector ( 0 , 0 , 0 ) ;
GetAttachment ( 3 , posGun , zeroVector ) ;
UTIL_MakeVectorsPrivate ( TourelleAngle ( ) , dirGun , NULL , NULL ) ;
FireBullets ( 1 , posGun , dirGun , VECTOR_CONE_5DEGREES , 8192 , BULLET_MONSTER_12MM ) ;
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , MITRAILLEUSE_SOUND , 1 , ATTN_NORM ) ;
if ( ! FStrEq ( STRING ( gpGlobals - > mapname ) , " l3m10 " ) & & ! FStrEq ( STRING ( gpGlobals - > mapname ) , " l3m12 " ) & & ! FStrEq ( STRING ( gpGlobals - > mapname ) , " l3m14 " ) )
{
CSprite * pSprite = CSprite : : SpriteCreate ( SPRITE_MUZ , posGun , TRUE ) ;
pSprite - > AnimateAndDie ( 15 ) ;
pSprite - > SetTransparency ( kRenderTransAdd , 255 , 255 , 255 , 255 , kRenderFxNoDissipation ) ;
pSprite - > SetAttachment ( edict ( ) , 4 ) ;
pSprite - > SetScale ( SPRITE_MUZ_SCALE ) ;
}
}
//sond du tank
UpdateSound ( ) ;
CSoundEnt : : InsertSound ( bits_SOUND_DANGER , pev - > origin + pev - > velocity * 2.5 , 150 , NEXTTHINK_TIME ) ;
CSoundEnt : : InsertSound ( bits_SOUND_PLAYER , pev - > origin , 2000 , 0.5 ) ;
}
void CTank : : StopThink ( void )
{
m_pCam - > SetPlayerTankView ( FALSE ) ;
m_pCam - > SetThink ( & CBaseEntity : : SUB_Remove ) ;
m_pCam - > pev - > nextthink = gpGlobals - > time + 0.1 ;
m_pCam = NULL ;
// if ( m_pPlayer->m_pActiveItem )
// m_pPlayer->m_pActiveItem->Deploy();
m_pPlayer - > m_iDrivingTank = FALSE ;
m_pPlayer - > m_iHideHUD & = ~ HIDEHUD_ALL ;
UTIL_SetOrigin ( m_pPlayer - > pev , Vector ( vecCamOrigin ( ) . x , vecCamOrigin ( ) . y , vecCamOrigin ( ) . z + 30 ) ) ;
bTankOn = 0 ;
m_pPlayer = NULL ;
pev - > nextthink = gpGlobals - > time + 0.1 ;
SetThink ( & CTank : : IdleThink ) ;
}
void CTank : : DeadThink ( void )
{
pev - > nextthink = gpGlobals - > time + 0.1 ;
pev - > sequence = 0 ;
// camera tournante
pev - > v_angle . y + = 3 ;
//rectification de la position de la camera
vecCamAim = UpdateCam ( ) ;
if ( m_pCam - > pev - > origin ! = vecCamAim )
m_pCam - > pev - > velocity = ( vecCamAim - m_pCam - > pev - > origin ) * 10 ;
UpdateCamAngle ( vecCamAim , NEXTTHINK_TIME ) ;
// sprites de feu
for ( int i = 0 ; i < 4 ; i + + )
{
CSprite * pSpr = CSprite : : SpriteCreate ( SPRITE_FEU , Vector ( pev - > origin . x , pev - > origin . y , pev - > origin . z + 100 ) , TRUE ) ;
pSpr - > SetScale ( SPRITE_FEU_SCALE ) ;
pSpr - > AnimateAndDie ( RANDOM_FLOAT ( 20 , 25 ) ) ;
pSpr - > SetTransparency ( kRenderTransAdd , 255 , 255 , 255 , 120 , kRenderFxNone ) ;
pSpr - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 50 , 50 ) , RANDOM_FLOAT ( - 50 , 50 ) , 140 /*RANDOM_FLOAT(130,150)*/ ) ;
}
for ( int i = 0 ; i < 1 ; i + + )
{
CSprite * pSpr = CSprite : : SpriteCreate ( SPRITE_SMOKEBALL , Vector ( pev - > origin . x , pev - > origin . y , pev - > origin . z + 100 ) , TRUE ) ;
pSpr - > SetScale ( SPRITE_SMOKEBALL_SCALE ) ;
pSpr - > AnimateAndDie ( RANDOM_FLOAT ( 3 , 4 ) ) ;
pSpr - > SetTransparency ( kRenderTransAlpha , 255 , 255 , 255 , 200 , kRenderFxNone ) ;
pSpr - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 50 , 50 ) , RANDOM_FLOAT ( - 50 , 50 ) , RANDOM_FLOAT ( 130 , 150 ) ) ;
}
}
void CTank : : TankDeath ( void )
{
bTankDead = 1 ;
pev - > sequence = 2 ; /*LookupSequence( "die" );*/
ResetSequenceInfo ( ) ;
m_pPlayer - > TakeDamage ( pev , pev , ( float ) 999 , DMG_CRUSH ) ; // mouru
pev - > velocity = pev - > avelocity = m_pTankBSP - > pev - > velocity = m_pTankBSP - > pev - > avelocity = Vector ( 0 , 0 , 0 ) ;
m_pTankBSP - > pev - > origin = pev - > origin ;
m_pTankBSP - > pev - > angles = pev - > angles ;
m_pCam - > pev - > velocity = m_pCam - > pev - > avelocity = Vector ( 0 , 0 , 0 ) ;
UpdateSound ( ) ;
SetThink ( & CTank : : DeadThink ) ;
pev - > nextthink = gpGlobals - > time + 29 / 21.0 ;
// maman, c'est quoi qu'a fait boum ?
EMIT_SOUND ( ENT ( pev ) , CHAN_AUTO , TANK_EXPLO_SOUND1 , 1 , ATTN_NORM ) ;
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , TANK_EXPLO_SOUND2 , 1 , ATTN_NORM ) ;
// sprites de feu - explosion
for ( int i = 0 ; i < 20 ; i + + )
{
CSprite * pSpr = CSprite : : SpriteCreate ( SPRITE_FEU , Vector ( pev - > origin . x , pev - > origin . y , pev - > origin . z + 50 ) , TRUE ) ;
pSpr - > SetScale ( SPRITE_FEU_SCALE * 2 ) ;
pSpr - > AnimateAndDie ( RANDOM_FLOAT ( 20 , 22 ) ) ;
pSpr - > SetTransparency ( kRenderTransAdd , 255 , 255 , 255 , 120 , kRenderFxNone ) ;
pSpr - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 150 , 150 ) , RANDOM_FLOAT ( - 150 , 150 ) , 100 /*RANDOM_FLOAT(130,150)*/ ) ;
}
// sprites de feu en colonne
for ( int i = 0 ; i < 6 ; i + + )
{
CSprite * pSpr = CSprite : : SpriteCreate ( SPRITE_FEU , Vector ( pev - > origin . x , pev - > origin . y , pev - > origin . z + 100 ) , TRUE ) ;
pSpr - > SetScale ( SPRITE_FEU_SCALE ) ;
pSpr - > AnimateAndDie ( RANDOM_FLOAT ( 20 , 25 ) ) ;
pSpr - > SetTransparency ( kRenderTransAdd , 255 , 255 , 255 , 120 , kRenderFxNone ) ;
pSpr - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 50 , 50 ) , RANDOM_FLOAT ( - 50 , 50 ) , 140 /*RANDOM_FLOAT(130,150)*/ ) ;
}
for ( int i = 0 ; i < 10 ; i + + )
{
CSprite * pSpr = CSprite : : SpriteCreate ( SPRITE_SMOKEBALL , Vector ( pev - > origin . x , pev - > origin . y , pev - > origin . z + 100 ) , TRUE ) ;
pSpr - > SetScale ( SPRITE_SMOKEBALL_SCALE ) ;
pSpr - > AnimateAndDie ( RANDOM_FLOAT ( 2 , 3 ) ) ;
pSpr - > SetTransparency ( kRenderTransAlpha , 255 , 255 , 255 , 255 , kRenderFxNone ) ;
pSpr - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 50 , 50 ) , RANDOM_FLOAT ( - 50 , 50 ) , RANDOM_FLOAT ( 50 , 50 ) ) ;
}
// gibs
for ( int i = 0 ; i < 20 ; i + + )
{
CGib * pGib = GetClassPtr ( ( CGib * ) NULL ) ;
pGib - > Spawn ( " models/mechgibs.mdl " ) ;
pGib - > m_bloodColor = DONT_BLEED ;
pGib - > pev - > body = RANDOM_LONG ( 1 , 5 ) ;
pGib - > pev - > origin = pev - > origin + Vector ( 0 , 0 , 250 ) ;
pGib - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 200 , 200 ) , RANDOM_FLOAT ( - 200 , 200 ) , RANDOM_FLOAT ( 0 , 400 ) ) ;
pGib - > pev - > avelocity = Vector ( RANDOM_FLOAT ( - 1000 , 1000 ) , RANDOM_FLOAT ( - 1000 , 1000 ) , RANDOM_FLOAT ( - 1000 , 1000 ) ) ;
pGib - > pev - > solid = SOLID_NOT ;
pGib - > SetThink ( & CBaseEntity : : SUB_Remove ) ;
pGib - > pev - > nextthink = gpGlobals - > time + 1 ;
}
//
for ( int i = 0 ; i < 10 ; i + + )
{
Create ( " spark_shower " , pev - > origin , Vector ( 0 , 0 , 1 ) , NULL ) ;
}
}
int CTank : : ModifAngles ( int angle )
{
if ( angle < 0 )
return 360 - fabs ( angle ) ;
else
return angle ;
}
void CTank : : UpdateCamAngle ( Vector vecNewPosition , float flTime )
{
Vector vecNewAngle ;
Vector zeroVector ( 0 , 0 , 0 ) ;
GetAttachment ( 2 , vecCamTarget , zeroVector ) ;
vecNewAngle = UTIL_VecToAngles ( vecCamTarget - vecNewPosition ) ;
vecNewAngle . x = - vecNewAngle . x ;
float distX = UTIL_AngleDistance ( m_pCam - > pev - > angles . x , vecNewAngle . x ) ;
m_pCam - > pev - > avelocity . x = - distX / flTime ;
float distY = UTIL_AngleDistance ( m_pCam - > pev - > angles . y , vecNewAngle . y ) ;
m_pCam - > pev - > avelocity . y = - distY / flTime ;
}
Vector CTank : : UpdateCam ( void )
{
TraceResult tr ;
int up = CAM_DIST_UP ;
int back = CAM_DIST_BACK ;
Vector Aim ;
UTIL_MakeVectors ( TourelleAngle ( ) ) ;
do
{
Aim = vecCamOrigin ( ) + gpGlobals - > v_up * up - gpGlobals - > v_forward * back ;
up - = CAM_DIST_UP / 20 ;
back - = CAM_DIST_BACK / 20 ;
UTIL_TraceLine ( vecCamOrigin ( ) , Aim , ignore_monsters , edict ( ) , & tr ) ;
}
while ( tr . vecEndPos ! = Aim /*|| CAM_DIST_UP == 0*/ ) ;
return Aim ;
}
void CTank : : Fire ( int canon )
{
Vector vecGun ;
Vector zeroVector ( 0 , 0 , 0 ) ;
GetAttachment ( canon , vecGun , zeroVector ) ;
if ( ! FStrEq ( STRING ( gpGlobals - > mapname ) , " l3m10 " ) & & ! FStrEq ( STRING ( gpGlobals - > mapname ) , " l3m12 " ) & & ! FStrEq ( STRING ( gpGlobals - > mapname ) , " l3m14 " ) )
{
CSprite * pSprite = CSprite : : SpriteCreate ( SPRITE_SMOKE , vecGun , TRUE ) ;
pSprite - > AnimateAndDie ( 15 ) ;
pSprite - > SetTransparency ( kRenderTransAdd , 255 , 255 , 255 , 255 , kRenderFxNoDissipation ) ;
pSprite - > SetAttachment ( edict ( ) , canon + 1 ) ;
pSprite - > SetScale ( SPRITE_SMOKE_SCALE ) ;
}
TraceResult tr ;
UTIL_MakeVectors ( TourelleAngle ( ) ) ;
UTIL_TraceLine ( vecGun , vecGun + gpGlobals - > v_forward * 8192 , dont_ignore_monsters , edict ( ) , & tr ) ;
// pas de dommages - la fonction standart donne un rayon 2.5 fois les dommages
// 250 * 2.5 = 625 - bcp trop grand
ExplosionCreate ( tr . vecEndPos , pev - > angles , NULL /*edict()*/ , 250 , FALSE ) ;
// on applique nous-m
: : RadiusDamage ( tr . vecEndPos , pev , pev , 300 , 300 , CLASS_NONE , DMG_BLAST ) ;
//effet de fum
EnvSmokeCreate ( tr . vecEndPos , 4 , 10 , 2 , 0 ) ;
/* // sprites de feu
for ( int i = 0 ; i < 4 ; i + + )
{
for ( int j = 0 ; j < 3 ; j + + )
{
CSprite * pSpr = CSprite : : SpriteCreate ( SPRITE_FEU , tr . vecEndPos + Vector ( 0 , 0 , 50 ) , TRUE ) ;
pSpr - > SetTransparency ( kRenderTransAdd , 255 , 255 , 255 , 180 , kRenderFxNone ) ;
pSpr - > pev - > scale = ( float ) ( ( float ) SPRITE_FEU_SCALE * 2 * ( 1 / ( i + 1 ) ) ) ;
pSpr - > pev - > framerate = RANDOM_FLOAT ( 18 , 24 ) ;
pSpr - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 50 , 50 ) * ( 3 - i ) / 3 , RANDOM_FLOAT ( - 50 , 50 ) * ( 3 - i ) / 3 , 50 * ( i ) ) ;
pSpr - > pev - > spawnflags | = SF_SPRITE_ONCE ;
pSpr - > TurnOn ( ) ;
}
}
*/
/* for ( int i=0; i<1; i++ )
{
CSprite * pSpr = CSprite : : SpriteCreate ( SPRITE_SMOKEBALL , Vector ( pev - > origin . x , pev - > origin . y , pev - > origin . z + 100 ) , TRUE ) ;
pSpr - > SetScale ( SPRITE_SMOKEBALL_SCALE ) ;
pSpr - > AnimateAndDie ( RANDOM_FLOAT ( 3 , 4 ) ) ;
pSpr - > SetTransparency ( kRenderTransAlpha , 255 , 255 , 255 , 200 , kRenderFxNone ) ;
pSpr - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 50 , 50 ) , RANDOM_FLOAT ( - 50 , 50 ) , RANDOM_FLOAT ( 130 , 150 ) ) ;
}
*/
//breakable sp
if ( FClassnameIs ( tr . pHit , " func_breakable " ) & & VARS ( tr . pHit ) - > spawnflags & SF_BREAK_TANKTOUCH )
{
CBreakable * pBreak = ( CBreakable * ) CBaseEntity : : Instance ( tr . pHit ) ;
if ( pBreak - > CheckTankPrev ( ) )
{
pBreak - > pev - > health = 0 ;
pBreak - > Killed ( pev , GIB_NORMAL ) ;
pBreak - > Die ( ) ;
}
}
}
Vector CTank : : TourelleAngle ( void )
{
UTIL_MakeVectors ( pev - > angles ) ;
Vector angle = UTIL_VecToAngles ( gpGlobals - > v_forward ) ;
angle . x + = pev - > v_angle . x ;
angle . y + = pev - > v_angle . y ;
angle . y = UTIL_AngleMod ( angle . y ) ;
angle . x = - angle . x ;
return angle ;
}
void CTank : : UpdateSound ( void )
{
if ( m_soundPlaying = = 0 )
{
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_STATIC , TANK_SOUND , 1.0 , ATTN_NORM , 0 , 100 ) ;
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_STREAM , CHENILLES_SOUND , 0.9 , ATTN_NORM , 0 , 100 ) ;
m_soundPlaying = 1 ;
}
else
{
//moteur
int pitch = ( int ) ( pev - > velocity . Length ( ) * 170 / 255 ) + 80 ;
pitch = pitch > 255 ? 255 : pitch ;
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_BODY , TANK_SOUND , 1.0 , ATTN_NORM , SND_CHANGE_PITCH | SND_CHANGE_VOL , pitch ) ;
//chenilles
int volume = ( ( int ) ( pev - > velocity . Length ( ) ) - 30 ) / 80 ;
volume = volume < 0 ? 0 : volume ;
volume = volume > 1 ? 1 : volume ;
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_STREAM , CHENILLES_SOUND , volume , ATTN_NORM , SND_CHANGE_PITCH | SND_CHANGE_VOL , 100 ) ;
}
}
int CTank : : Save ( CSave & save )
{
if ( ! CBaseMonster : : Save ( save ) )
return 0 ;
return save . WriteFields ( " CTank " , this , m_SaveData , ARRAYSIZE ( m_SaveData ) ) ;
}
int CTank : : Restore ( CRestore & restore ) // s execute lors du chargement rapide
{
if ( ! CBaseMonster : : Restore ( restore ) )
return 0 ;
int status = restore . ReadFields ( " CTank " , this , m_SaveData , ARRAYSIZE ( m_SaveData ) ) ;
//-----------------------
ALERT ( at_console , " TANK RESTORE ----------------- \n " ) ;
// restoration de la camera
bSetView = 1 ;
// restoration du tank
CBaseEntity * pFind = UTIL_FindEntityByClassname ( NULL , " info_tank_model " ) ;
while ( pFind ! = NULL & & pFind = = this )
pFind = UTIL_FindEntityByClassname ( pFind , " info_tank_model " ) ;
// chargement
if ( pFind = = NULL )
{
ALERT ( at_console , " TANK RESTORE : il n'y a qu'un tankmodel : simple chargement \n " ) ;
return status ;
}
// changement de niveau
ALERT ( at_console , " TANK RESTORE : autre tankmodel : changement de niveau \n " ) ;
CTank * pModelFound = ( CTank * ) pFind ;
m_pTankBSP = pModelFound - > m_pTankBSP ; // changement de tankbsp
m_pTankBSP - > m_pTankModel = this ;
pModelFound - > SetThink ( & CBaseEntity : : SUB_Remove ) ; // destruction du tankmodel inutile
pModelFound - > pev - > nextthink = gpGlobals - > time + 0.1 ;
pModelFound - > pev - > rendermode = kRenderTransTexture ;
pModelFound - > pev - > renderamt = 0 ;
m_pTankBSP - > pev - > angles = pev - > angles ;
m_pTankBSP - > pev - > origin = pev - > origin ;
// tite boite
edict_t * pentTrouve ;
CBaseEntity * pTrouve ;
CBasePlayer * pPlayer = ( CBasePlayer * ) UTIL_FindEntityByClassname ( NULL , " player " ) ;
pentTrouve = FIND_ENTITY_BY_CLASSNAME ( NULL , " info_teleport_destination " ) ;
if ( pentTrouve = = NULL )
{
ALERT ( at_console , " info_tank_model : pas de teleport destination !!! \n " ) ;
return status ;
}
else
{
pTrouve = CBaseEntity : : Instance ( pentTrouve ) ;
Vector vecTeleport = pTrouve - > pev - > origin ;
UTIL_SetOrigin ( pPlayer - > pev , vecTeleport ) ;
}
return status ;
}
//----------------------------------------------------------
// mine anti char
class CMineAC : public CBaseEntity
{
public :
void Spawn ( void ) ;
void Precache ( void ) ;
void EXPORT MineThink ( void ) ;
} ;
LINK_ENTITY_TO_CLASS ( monster_mine_ac , CMineAC ) ;
void CMineAC : : Precache ( void )
{
PRECACHE_MODEL ( " models/dxmine.mdl " ) ;
}
void CMineAC : : Spawn ( void )
{
Precache ( ) ;
SET_MODEL ( ENT ( pev ) , " models/dxmine.mdl " ) ;
UTIL_SetSize ( pev , VEC_HUMAN_HULL_MIN , VEC_HUMAN_HULL_MAX ) ;
UTIL_SetOrigin ( pev , pev - > origin ) ;
pev - > movetype = MOVETYPE_NOCLIP ;
pev - > solid = SOLID_NOT ;
SetThink ( & CMineAC : : MineThink ) ;
pev - > nextthink = gpGlobals - > time + 0.1 ;
}
void CMineAC : : MineThink ( void )
{
pev - > nextthink = gpGlobals - > time + 0.1 ;
TraceResult tr ;
UTIL_TraceHull ( pev - > origin , pev - > origin + Vector ( 0 , 0 , 20 ) , dont_ignore_monsters , head_hull , edict ( ) , & tr ) ;
if ( tr . pHit = = NULL )
return ;
if ( ( tr . pHit - > v . flags & FL_MONSTER ) | | ( tr . pHit - > v . flags & FL_CLIENT ) )
{
Vector zeroVector ( 0 , 0 , 0 ) ;
ExplosionCreate ( pev - > origin + Vector ( 0 , 0 , 30 ) , zeroVector , edict ( ) , 200 , TRUE ) ;
SetThink ( & CBaseEntity : : SUB_Remove ) ;
}
}
//-------------------------------------------------------
// Tank Charger
class CTankCharger : public CBaseEntity
{
public :
void Spawn ( void ) ;
void EXPORT ChargerThink ( void ) ;
} ;
LINK_ENTITY_TO_CLASS ( func_tank_charger , CTankCharger ) ;
void CTankCharger : : Spawn ( void )
{
pev - > movetype = MOVETYPE_NONE ;
pev - > solid = SOLID_TRIGGER ;
SET_MODEL ( ENT ( pev ) , STRING ( pev - > model ) ) ; // set size and link into world
pev - > effects | = EF_NODRAW ;
SetThink ( & CTankCharger : : ChargerThink ) ;
pev - > nextthink = gpGlobals - > time + 0.1 ;
}
void CTankCharger : : ChargerThink ( void )
{
pev - > nextthink = gpGlobals - > time + 0.1 ;
TraceResult tr ;
UTIL_TraceHull ( ( pev - > mins + pev - > maxs ) * 0.5 , ( pev - > mins + pev - > maxs ) * 0.5 + Vector ( 0 , 0 , 100 ) , dont_ignore_monsters , head_hull , edict ( ) , & tr ) ;
if ( tr . pHit = = NULL )
return ;
if ( ( tr . pHit - > v . flags & FL_MONSTER ) & & FClassnameIs ( tr . pHit , " vehicle_tank " ) )
{
CTankBSP * pBsp = ( CTankBSP * ) CBaseEntity : : Instance ( tr . pHit ) ;
pBsp - > pev - > health = Q_min ( pBsp - > pev - > health + TANK_RECHARGE , TANK_LIFE ) ;
// rafraichissement de l'affichage
if ( pBsp - > m_pTankModel - > bTankOn = = TRUE )
pBsp - > m_pTankModel - > m_pCam - > SetPlayerTankView ( TRUE ) ;
}
}