mirror of
https://github.com/YGGverse/hlsdk-portable.git
synced 2025-03-13 05:51:19 +00:00
1618 lines
39 KiB
C++
1618 lines
39 KiB
C++
/****************************************************************************
|
|
* *
|
|
* 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 ¢er, 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 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|