Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
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.

1618 lines
39 KiB

/****************************************************************************
* *
* 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 );
}
}