Rebase step 2: add changes automatically patched by diffing HLSDK 2.3 and Decay trees

This commit is contained in:
Alibek Omarov 2024-04-03 07:02:57 +03:00
parent dd15f7a392
commit 988c6757dd
45 changed files with 4364 additions and 30 deletions

View File

@ -898,7 +898,7 @@ int CHudAmmo::Draw( float flTime )
x += AmmoWidth / 2;
UnpackRGB( r,g,b, RGB_YELLOWISH );
UnpackRGB( r,g,b, gHUD.uColor );
// draw the | bar
FillRGBA( x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a );

View File

@ -79,6 +79,15 @@ void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking);
void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf );
void DLLEXPORT HUD_MobilityInterface( mobile_engfuncs_t *gpMobileEngfuncs );
}
/*
// SCREEN GLOW
extern bool InitScreenGlow();
extern void RenderScreenGlow();
*/
// CAMERA EFFECT
extern bool InitCameraEffect();
extern void RenderCameraEffect();
extern void GrabCameraTexture();
/*
================================
@ -302,6 +311,14 @@ redraw the HUD.
int DLLEXPORT HUD_Redraw( float time, int intermission )
{
// check if we are in OpenGl mode
if (IEngineStudio.IsHardware() == 1)
{
//RenderScreenGlow(); // SCREEN GLOW
if (gHUD.m_iCamMode == CAM_ON)
RenderCameraEffect();
}
gHUD.Redraw( time, intermission );
return 1;

View File

@ -1696,6 +1696,287 @@ void EV_SnarkFire( event_args_t *args )
// SQUEAK END
//======================
//======================
// VORTI START
//======================
enum vorti_e {
SLAVE_IDLE1 = 0,
SLAVE_IDLE2,
SLAVE_ATTACK1HIT,
SLAVE_ATTACK1MISS,
SLAVE_ATTACK2MISS,
SLAVE_ATTACK2HIT,
SLAVE_ATTACK3MISS,
SLAVE_ATTACK3HIT,
SLAVE_CHARGE,
SLAVE_CHARGE_LOOP,
SLAVE_ZAP,
SLAVE_RETURN
};
int g_iVortSwing;
//Only predict the miss sounds, hit sounds are still played
//server side, so players don't get the wrong idea.
void EV_Vorti( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
idx = args->entindex;
VectorCopy( args->origin, origin );
//Play Swing sound
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "zombie/claw_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM);
if ( EV_IsLocal( idx ) )
{
gEngfuncs.pEventAPI->EV_WeaponAnimation( SLAVE_ATTACK1MISS, 1 );
switch( (g_iVortSwing++) % 3 )
{
case 0:
gEngfuncs.pEventAPI->EV_WeaponAnimation ( SLAVE_ATTACK1MISS, 1 ); break;
case 1:
gEngfuncs.pEventAPI->EV_WeaponAnimation ( SLAVE_ATTACK2MISS, 1 ); break;
case 2:
gEngfuncs.pEventAPI->EV_WeaponAnimation ( SLAVE_ATTACK3MISS, 1 ); break;
}
}
}
/*
float r = 255.0f;
float g = 180.0f;
float b = 96.0f;
R_BeamEntPoint:
int startEnt,
float * end,
int modelIndex,
float life,
float width,
float amplitude,
float brightness,
float speed,
int startFrame,
float framerate,
float r, float g, float b
pVortiBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex,
99999, ///life
2.0, //width
0.4, // ampl
64 / 255, //bright
55, //speed
0, 0,
r, g, b );
*/
//#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch
void EV_SpinVorti( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int iSoundState = 0;
int pitch;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
pitch = args->iparam1;
//iSoundState = args->bparam1 ? SND_CHANGE_PITCH : 0;
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "debris/zap1.wav", 1.0, ATTN_NORM, iSoundState, pitch );
}
/*
==============================
EV_StopPreviousGauss
==============================
*/
void EV_StopPreviousVorti( int idx )
{
// Make sure we don't have a gauss spin event in the queue for this guy
gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/vortispin.sc" );
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_WEAPON, "debris/zap1.wav" );
}
void EV_FireVorti( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
float flDamage = args->fparam1;
int primaryfire = args->bparam1;
int m_fPrimaryFire = args->bparam1;
int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME;
vec3_t vecSrc;
vec3_t vecDest;
edict_t *pentIgnore;
pmtrace_t tr, beam_tr;
float flMaxFrac = 1.0;
int nTotal = 0;
int fHasPunched = 0;
int fFirstBeam = 1;
int nMaxHits = 1;
physent_t *pEntity;
int m_iBeam, m_iGlow, m_iBalls;
vec3_t up, right, forward;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
if ( args->bparam2 )
{
EV_StopPreviousVorti( idx );
return;
}
//Con_Printf( "Firing vorti with %f\n", flDamage );
EV_GetGunPosition( args, vecSrc, origin );
m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/lgtning.spr" );
m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" );
AngleVectors( angles, forward, right, up );
VectorMA( vecSrc, 8192, forward, vecDest );
if ( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, -2.0 );
gEngfuncs.pEventAPI->EV_WeaponAnimation( SLAVE_ZAP, 2 );
if ( m_fPrimaryFire == false )
g_flApplyVel = flDamage;
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/electro4.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) );
while (flDamage > 10 && nMaxHits > 0)
{
nMaxHits--;
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr );
gEngfuncs.pEventAPI->EV_PopPMStates();
if ( tr.allsolid )
break;
if ( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
}
fFirstBeam = 0;
gEngfuncs.pEfxAPI->R_BeamEntPoint(
idx | 0x1000,
tr.endpos,
m_iBeam,
0.3,
3.0,
0.5, // noise
1.0,
55,
0,
0,
0.5, 1, 0//180, 255, 96
);
gEngfuncs.pEfxAPI->R_BeamEntPoint(
idx | 0x2000,
tr.endpos,
m_iBeam,
0.3,
3.0,
0.5, // noise
1.0,
55,
0,
0,
0.5, 1, 0//180, 255, 96
);
pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent );
if ( pEntity == NULL )
break;
if ( pEntity->solid == SOLID_BSP )
{
float n;
pentIgnore = NULL;
n = -DotProduct( tr.plane.normal, forward );
// tunnel
EV_HLDM_DecalGunshot( &tr, BULLET_MONSTER_12MM );
//gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT );
//gEngfuncs.pEfxAPI->R_FunnelSprite( tr.endpos, m_iGlow, false );
gEngfuncs.pEfxAPI->R_SparkShower( tr.endpos );
// limit it to one hole punch
if (fHasPunched)
{
break;
}
fHasPunched = 1;
{
// slug doesn't punch through ever with primary
// fire, so leave a little glowy bit and make some balls
//gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT );
vec3_t fwd;
VectorAdd( tr.endpos, tr.plane.normal, fwd );
//gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 8, 0.6, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100,
// 255, 200 );
}
flDamage = 0;
}
else
{
VectorAdd( tr.endpos, forward, vecSrc );
}
}
}
//======================
// VORTI END
//======================
void EV_TrainPitchAdjust( event_args_t *args )
{
int idx;

View File

@ -88,8 +88,9 @@ int CHudHealth::VidInit( void )
{
m_hSprite = 0;
m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1;
m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" );// + 1;
m_HUD_cross = gHUD.GetSpriteIndex( "cross" );
m_HUD_alien = gHUD.GetSpriteIndex( "islave_health" );
giDmgHeight = gHUD.GetSpriteRect( m_HUD_dmg_bio ).right - gHUD.GetSpriteRect( m_HUD_dmg_bio ).left;
giDmgWidth = gHUD.GetSpriteRect( m_HUD_dmg_bio ).bottom - gHUD.GetSpriteRect( m_HUD_dmg_bio ).top;

View File

@ -330,6 +330,7 @@ void CBasePlayerItem::Drop( void ) { }
void CBasePlayerItem::Kill( void ) { }
void CBasePlayerItem::Holster( int skiplocal ) { }
void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) { }
void CBasePlayerItem::KeyValue( KeyValueData *pkvd ) { }
int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { return 0; }
int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { return FALSE; }
int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { return 0; }

View File

@ -55,6 +55,7 @@ vec3_t previousorigin;
// HLDM Weapon placeholder entities.
CGlock g_Glock;
CCrowbar g_Crowbar;
CVortiHands g_VortiHands;
CPython g_Python;
CMP5 g_Mp5;
CCrossbow g_Crossbow;
@ -725,6 +726,7 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm
case WEAPON_SNARK:
pWeapon = &g_Snark;
break;
}
// Store pointer to our destination entity_state_t so we can get our origin, etc. from it

View File

@ -139,6 +139,33 @@ int __MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf )
return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf );
}
int __MsgFunc_DecayName(const char *pszName, int iSize, void *pbuf )
{
return gHUD.MsgFunc_DecayName( pszName, iSize, pbuf );
}
int __MsgFunc_LensFlare(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_LensFlare(pszName, iSize, pbuf );
}
int __MsgFunc_AimFrame(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_AimFrame(pszName, iSize, pbuf );
}
int __MsgFunc_ChangePlr(const char *pszName, int iSize, void *pbuf )
{
gHUD.MsgFunc_ChangePlayer(pszName, iSize, pbuf );
return 1;
}
int __MsgFunc_Camera(const char *pszName, int iSize, void *pbuf)
{
gHUD.MsgFunc_Camera( pszName, iSize, pbuf );
return 1;
}
// TFFree Command Menu
void __CmdFunc_OpenCommandMenu( void )
{
@ -331,6 +358,8 @@ void CHud::Init( void )
HOOK_MESSAGE( ViewMode );
HOOK_MESSAGE( SetFOV );
HOOK_MESSAGE( Concuss );
HOOK_MESSAGE( Camera );
HOOK_MESSAGE( DecayName );
// TFFree CommandMenu
HOOK_COMMAND( "+commandmenu", OpenCommandMenu );
@ -364,8 +393,14 @@ void CHud::Init( void )
HOOK_MESSAGE( ResetFade );
#endif
HOOK_MESSAGE( LensFlare );
HOOK_MESSAGE( AimFrame );
HOOK_MESSAGE( ChangePlr );
// VGUI Menus
HOOK_MESSAGE( VGUIMenu );
HOOK_MESSAGE( Notepad );
HOOK_MESSAGE( SparePlayer );
CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); // controls whether or not to suicide immediately on TF class switch
CVAR_CREATE( "hud_takesshots", "0", FCVAR_ARCHIVE ); // controls whether or not to automatically take screenshots at the end of a round
@ -373,6 +408,8 @@ void CHud::Init( void )
m_iLogo = 0;
m_iFOV = 0;
m_iLensIndex = 0;
m_iFrameIndex = 0;
CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", FCVAR_ARCHIVE );
CVAR_CREATE( "cl_autowepswitch", "1", FCVAR_ARCHIVE | FCVAR_USERINFO );
@ -475,6 +512,9 @@ void CHud::VidInit( void )
m_scrinfo.iSize = sizeof(m_scrinfo);
GetScreenInfo( &m_scrinfo );
// Set HUD color
uColor = RGB_YELLOWISH;
// ----------
// Load Sprites
// ---------
@ -590,6 +630,20 @@ void CHud::VidInit( void )
m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top;
//load sprites for lens flare effect and for selection frame
for (int i=0;i<9;i++)
{
m_hsprLens[i] = NULL;
char szName[32];
sprintf(szName, "sprites/lens_%d.spr",i);
if (m_hsprLens[i] == 0)
m_hsprLens[i] = LoadSprite(szName);
}
m_hsprFrame = LoadSprite("sprites/bracket.spr");
m_iFrameSize = SPR_Width(m_hsprFrame,0);
pFrameTexture = gEngfuncs.GetSpritePointer( m_hsprFrame );
m_Ammo.VidInit();
m_Health.VidInit();
m_Spectator.VidInit();
@ -626,6 +680,46 @@ int CHud::MsgFunc_Logo( const char *pszName, int iSize, void *pbuf )
return 1;
}
int CHud::MsgFunc_LensFlare(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
m_iLensIndex = READ_BYTE();
return 1;
}
int CHud::MsgFunc_AimFrame(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
m_iFrameIndex = READ_BYTE();
m_iFrameKind = READ_BYTE();
m_vAimFrameCoords.x = READ_COORD();
m_vAimFrameCoords.y = READ_COORD();
m_vAimFrameCoords.z = READ_COORD();
m_vAimFrameMaxs.x = READ_COORD();
m_vAimFrameMaxs.y = READ_COORD();
m_vAimFrameMaxs.z = READ_COORD();
return 1;
}
int CHud::MsgFunc_ChangePlayer(const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int m_iDecayId = READ_BYTE();
if (m_iDecayId == 1)
uColor = RGB_SILVERISH;
else
uColor = RGB_YELLOWISH;
return 1;
}
float g_lastFOV = 0.0;
/*

View File

@ -25,6 +25,7 @@
#define RGB_YELLOWISH 0x00FFA000 //255,160,0
#define RGB_REDISH 0x00FF1010 //255,160,0
#define RGB_GREENISH 0x0000A000 //0,160,0
#define RGB_SILVERISH 0x00D4D4D4 //
#include "wrect.h"
#include "cl_dll.h"
@ -58,6 +59,7 @@ typedef struct cvar_s cvar_t;
#define HUD_ACTIVE 1
#define HUD_INTERMISSION 2
#define HUD_ALIEN 4
#define MAX_PLAYER_NAME_LENGTH 32
@ -421,6 +423,54 @@ private:
int m_iWidth; // width of the battery innards
};
//
//-----------------------------------------------------
//
class CHudModeIcon: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
void Reset( void );
int MsgFunc_ChangeMode(const char *pszName, int iSize, void *pbuf );
private:
HSPRITE m_hSpriteStand;
HSPRITE m_hSpriteRun;
HSPRITE m_hSpriteCrouch;
HSPRITE m_hSpriteJump;
HSPRITE m_hActiveSprite;
wrect_t *m_prcStand;
wrect_t *m_prcRun;
wrect_t *m_prcCrouch;
wrect_t *m_prcJump;
wrect_t *m_prcActiveRect;
int m_fMode;
};
class CHudAlienCrosshair: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
void Reset( void );
int MsgFunc_AlienState(const char *pszName, int iSize, void *pbuf );
private:
HSPRITE m_hCrosshair[4];
wrect_t *m_prcCrosshair[4];
HSPRITE m_hActiveSprite;
wrect_t *m_prcActiveRect;
int m_iState;
};
//
//-----------------------------------------------------
//
@ -542,7 +592,16 @@ private:
int m_iSpriteCountAllRes;
float m_flMouseSensitivity;
int m_iConcussionEffect;
HSPRITE m_hsprLens[9];//lens flare sprite data
HSPRITE m_hsprFrame;
int m_iLensIndex;
int m_iFrameIndex;//index of entity to draw frame around
int m_iFrameKind; //frame hint index in names array
int m_iFrameSize;
const model_s *pFrameTexture;//frame texture for tri_api
//vec3_t m_vAimFrameCoords; //for selection frame
//vec3_t m_vAimFrameMaxs; //for selection frame
public:
HSPRITE m_hsprCursor;
float m_flTime; // the current client time
@ -557,6 +616,17 @@ public:
int m_iRes;
cvar_t *m_pCvarStealMouse;
cvar_t *m_pCvarDraw;
Vector m_vecCamPos; // CAM
int m_iCamMode; // CAM
unsigned long uColor;
// TEXTURES
unsigned int g_uiScreenTex;
unsigned int g_uiGlowTex;
unsigned int g_uiCameraTex;
vec3_t m_vAimFrameCoords; //for selection frame
vec3_t m_vAimFrameMaxs; //for selection frame
int m_iFontHeight;
int DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b );
@ -635,6 +705,7 @@ public:
int m_iWeaponBits;
int m_fPlayerDead;
int m_iIntermission;
bool m_bAlienMode;
// sprite indexes
int m_HUD_number_0;

View File

@ -12,6 +12,11 @@
* without written permission from Valve LLC.
*
****/
/***
*
* (C) 2008 Vyacheslav Dzhura
*
****/
//
// hud_msg.cpp
//

View File

@ -94,6 +94,80 @@ void CHud::Think( void )
}
}
void ReturnFrameHint(char* szHint,int Id)
{
switch(Id){
case 0:
sprintf(szHint,"Button");
break;
case 1:
sprintf(szHint,"Object");
break;
case 2:
sprintf(szHint,"Item");
break;
case 3:
sprintf(szHint,"File");
break;
case 4:
sprintf(szHint,"Documents");
break;
case 5:
sprintf(szHint,"Book");
break;
case 6:
sprintf(szHint,"Monitor");
break;
case 7:
sprintf(szHint,"Computer");
break;
case 8:
sprintf(szHint,"Compact Disc");
break;
case 9:
sprintf(szHint,"Extinguisher");
break;
case 10:
sprintf(szHint,"Security Card");
break;
case 11:
sprintf(szHint,"Key");
break;
case 12:
sprintf(szHint,"Syringe");
break;
case 13:
sprintf(szHint,"Cleansuit");
break;
case 14:
sprintf(szHint,"Wrench");
break;
case 15:
sprintf(szHint,"Retinal Scanner");
break;
case 16:
sprintf(szHint,"Health Charger");
break;
case 17:
sprintf(szHint,"HEV Charger");
break;
default:
sprintf(szHint,"Unknown");
}
}
void DrawFrameCorner(int x,int y,int u1,int u2,int u3,int u4,int v1,int v2,int v3,int v4)
{
gEngfuncs.pTriAPI->TexCoord2f( u1, v1 );
gEngfuncs.pTriAPI->Vertex3f( x, y, 0.0 );
gEngfuncs.pTriAPI->TexCoord2f( u2, v2 );
gEngfuncs.pTriAPI->Vertex3f( x, y+g_iFrameSize, 0.0 );
gEngfuncs.pTriAPI->TexCoord2f( u3, v3 );
gEngfuncs.pTriAPI->Vertex3f( x+g_iFrameSize, y+g_iFrameSize, 0.0 );
gEngfuncs.pTriAPI->TexCoord2f( u4, v4 );
gEngfuncs.pTriAPI->Vertex3f( x+g_iFrameSize, y, 0.0 );
}
// Redraw
// step through the local data, placing the appropriate graphics & text as appropriate
// returns 1 if they've changed, 0 otherwise
@ -170,6 +244,12 @@ int CHud::Redraw( float flTime, int intermission )
if( pList->p->m_iFlags & HUD_INTERMISSION )
pList->p->Draw( flTime );
}
} else
{ // alien mode!!!
if ( pList->p->m_iFlags & HUD_ALIEN )
if ( (pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL) )
pList->p->Draw( flTime );
}
pList = pList->pNext;
}
@ -196,6 +276,137 @@ int CHud::Redraw( float flTime, int intermission )
SPR_DrawAdditive( i, x, y, NULL );
}
// draw selection frame around entity
if (m_iFrameIndex !=0)
{
vec3_t v_center, v_maxs;
gEngfuncs.pTriAPI->WorldToScreen(m_vAimFrameCoords,v_center);
gEngfuncs.pTriAPI->WorldToScreen(m_vAimFrameMaxs,v_maxs);
v_center[0] = XPROJECT(v_center[0]);
v_center[1] = YPROJECT(v_center[1]);
v_center[2] = 0.0f;
v_maxs[0] = XPROJECT(v_maxs[0]);
v_maxs[1] = YPROJECT(v_maxs[1]);
v_maxs[2] = 0.0f;
g_iFrameSize = m_iFrameSize;
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)pFrameTexture, 0 );
gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
gEngfuncs.pTriAPI->Begin( TRI_QUADS );
if (v_center[0]>v_maxs[0])
{
//right bottom
DrawFrameCorner(v_center[0],v_center[1],1,1,0,0,1,0,0,1);
//left bottom
DrawFrameCorner(v_center[0]-(v_center[0]-v_maxs[0]),v_center[1],1,0,0,1,0,0,1,1);
//left up
DrawFrameCorner(v_maxs[0], v_maxs[1],0,0,1,1,0,1,1,0);
//left right
DrawFrameCorner(v_maxs[0]+(v_center[0]-v_maxs[0]),v_maxs[1],0,1,1,0,1,1,0,0);
}
else
{
//right bottom
DrawFrameCorner(v_center[0],v_center[1],1,0,0,1,0,0,1,1);
//left bottom
DrawFrameCorner(v_center[0]-(v_center[0]-v_maxs[0]),v_center[1],1,1,0,0,1,0,0,1);
//left up
DrawFrameCorner(v_maxs[0],v_maxs[1],0,1,1,0,1,1,0,0);
//left right
DrawFrameCorner(v_maxs[0]+(v_center[0]-v_maxs[0]),v_maxs[1],0,0,1,1,0,1,1,0);
}
gEngfuncs.pTriAPI->End();
gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
//to make that working, modify in decay.dll player.cpp blank message value of frame kind to -1
//if (!m_iFrameKind==-1)
if (m_iFrameKind != -1)
{
char szMes[25];
ReturnFrameHint(szMes,m_iFrameKind);
gHUD.DrawHudString( v_maxs[0]+5, v_maxs[1]+4, ScreenWidth, szMes, 255, 180, 0 );
}
}
/*
char szMes[255];
if ( m_bAlienMode )
sprintf( szMes, "Alien slave (vortigaunt) mode on" );
else
sprintf( szMes, "Normal mode" );
*/
//ReturnFrameHint(szMes,m_iFrameKind);
// gHUD.DrawHudString( 10, 10, 512, szMes, 255, 180, 0 );
//draw sun
if (m_iLensIndex !=0)
{
vec3_t screen,ors;
float tN[9];
tN[0]=1.0;
tN[1]=0.8;
tN[2]=0.7;
tN[3]=0.5;
tN[4]=0.4;
tN[5]=0.25;
tN[6]=0.1;
tN[7]=-0.1;
tN[8]=-0.2;
cl_entity_t *ent = gEngfuncs.GetEntityByIndex(m_iLensIndex);
if (ent)
{
vec3_t forward, right, up;
AngleVectors ( ent->angles, forward, right, up );//get f/r/u vectors
pmtrace_t tr;
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( (float *)&v_origin, v_origin + (forward+up)/2 * 8192, PM_GLASS_IGNORE, -1, &tr );
//pmtrace_t tr = *(gEngfuncs.PM_TraceLine( (float *)&v_origin, v_origin + (forward+up)/2 * 8192, 0, 2, -1 )); // PM_GLASS_IGNORE
if (gEngfuncs.PM_PointContents( tr.endpos, NULL )!=CONTENTS_SKY)
{
return 0;
}
if (!gEngfuncs.pTriAPI->WorldToScreen(tr.endpos,ors))
{
int LWidth, LHeight;
LWidth = NULL;
LHeight = NULL;
ors[0] = XPROJECT(ors[0]);
ors[1] = YPROJECT(ors[1]);
ors[2] = 0.0f;
if (ors[0]<0 || ors[0]>ScreenWidth) return 0;
if (ors[1]<0 || ors[1]>ScreenHeight) return 0;
for (int i=0;i<9;i++)
{
if (i!=0)
SPR_Set(m_hsprLens[i], 50, 50, 50); //was 250
else
SPR_Set(m_hsprLens[i], 100, 100, 100); //make sun brighter then other lens
LWidth = SPR_Width(m_hsprLens[i],0);
LHeight = SPR_Height(m_hsprLens[i],0);
screen=ors;
screen[0] = ScreenWidth/2+(screen[0]-ScreenWidth/2)*tN[i];
screen[1] = ScreenHeight/2+(screen[1]-ScreenHeight/2)*tN[i];
screen[0] = screen[0]-(LWidth/2);
screen[1] = screen[1]-(LHeight/2);
SPR_DrawAdditive(0, screen[0],screen[1], NULL);
}
}
}
}
/*
if( g_iVisibleMouse )
{

View File

@ -1106,8 +1106,9 @@ float already_chosen_map;
#define MENU_CLASSHELP 6
#define MENU_CLASSHELP2 7
#define MENU_REPEATHELP 8
#define MENU_SPECHELP 9
#define MENU_NOTEPAD 10
#define MENU_SPAREPLAYERWINDOW 11
#define MENU_SPY 12

View File

@ -5,13 +5,14 @@
// $NoKeywords: $
//=============================================================================
// Triangle rendering, if any
#include <windows.h>
//#include <gl/gl.h>
#include "hud.h"
#include "cl_util.h"
// Triangle rendering apis are in gEngfuncs.pTriAPI
//#include "com_model.h"
#include "const.h"
#include "entity_state.h"
#include "cl_entity.h"

View File

@ -269,7 +269,7 @@ CSchemeManager::CSchemeManager( int xRes, int yRes )
}
if ( !pScheme->fontName[0] )
{
strcpy( pScheme->fontName, "Arial" );
strcpy( pScheme->fontName, "Trebuchet MS" ); // Vyacheslav Dzhura: was Arial
}
}
@ -353,7 +353,7 @@ buildDefaultFont:
{
currentScheme = 0;
strcpy( tmpSchemes[0].schemeName, "Default Scheme" );
strcpy( tmpSchemes[0].fontName, "Arial" );
strcpy( tmpSchemes[0].fontName, "Trebuchet MS" ); //Hoaxer: was Arial
tmpSchemes[0].fontSize = 0;
tmpSchemes[0].fgColor[0] = tmpSchemes[0].fgColor[1] = tmpSchemes[0].fgColor[2] = tmpSchemes[0].fgColor[3] = 255;
tmpSchemes[0].armedFgColor[0] = tmpSchemes[0].armedFgColor[1] = tmpSchemes[0].armedFgColor[2] = tmpSchemes[0].armedFgColor[3] = 255;

View File

@ -513,6 +513,8 @@ TeamFortressViewport::TeamFortressViewport( int x, int y, int wide, int tall ) :
m_pSpectatorPanel = NULL;
m_pCurrentMenu = NULL;
m_pCurrentCommandMenu = NULL;
m_pNotepad = NULL;
m_pSparePlayerWindow = NULL;
Initialize();
addInputSignal( new CViewPortInputHandler );
@ -567,6 +569,8 @@ TeamFortressViewport::TeamFortressViewport( int x, int y, int wide, int tall ) :
App::getInstance()->setScheme( pScheme );
// VGUI MENUS
CreateNotepad();
CreateSparePlayerWindow();
CreateTeamMenu();
CreateClassMenu();
CreateSpectatorMenu();
@ -618,6 +622,14 @@ void TeamFortressViewport::Initialize( void )
// Spectator menu doesn't need initializing
m_pSpectatorPanel->setVisible( false );
}
if (m_pNotepad)
{
m_pNotepad->Initialize();
}
if (m_pSparePlayerWindow)
{
m_pSparePlayerWindow->Initialize();
}
// Make sure all menus are hidden
HideVGUIMenu();
@ -1461,6 +1473,29 @@ CMenuPanel *TeamFortressViewport::CreateTextWindow( int iTextToShow )
//================================================================
// VGUI Menus
void TeamFortressViewport::DisplayNotepad( char* szText, int iTitle )
{
// Don't open window in demo playback
if ( gEngfuncs.pDemoAPI->IsPlayingback() )
return;
if (m_pCurrentMenu)
{
CMenuPanel *pMenu = m_pCurrentMenu;
while (pMenu != NULL)
{
if (pMenu->GetMenuID() == MENU_NOTEPAD )
return;
pMenu = pMenu->GetNextMenu();
}
}
strcpy(m_pNotepad->szText, szText);
sprintf(m_pNotepad->szTitle,"#NotepadHeader%i",iTitle);
ShowNotepad();
}
void TeamFortressViewport::ShowVGUIMenu( int iMenu )
{
CMenuPanel *pNewMenu = NULL;
@ -1513,6 +1548,10 @@ void TeamFortressViewport::ShowVGUIMenu( int iMenu )
case MENU_CLASS:
pNewMenu = ShowClassMenu();
break;
//case MENU_NOTEPAD:
// m_pNotepad->Reset();
// pNewMenu = m_pNotepad;
// break;
default:
break;
@ -1613,6 +1652,63 @@ void TeamFortressViewport::CreateTeamMenu()
m_pTeamMenu->setVisible( false );
}
//======================================================================================
// NOTEPAD
//======================================================================================
// Bring up the Notepad
void TeamFortressViewport::ShowNotepad()
{
if (m_pNotepad)
{
m_pNotepad->SetMenuID( MENU_NOTEPAD );
m_pNotepad->SetActive( true );
m_pNotepad->setParent( this );
m_pCurrentMenu = m_pNotepad;
m_pCurrentMenu->Reset();
m_pCurrentMenu->Open();
}
UpdateCursorState();
}
void TeamFortressViewport::ShowSparePlayerWindow()
{
if (m_pSparePlayerWindow)
{
m_pSparePlayerWindow->SetMenuID( MENU_SPAREPLAYERWINDOW );
m_pSparePlayerWindow->SetActive( true );
m_pSparePlayerWindow->setParent( this );
m_pCurrentMenu = m_pSparePlayerWindow;
m_pCurrentMenu->Reset();
m_pCurrentMenu->Open();
}
UpdateCursorState();
}
bool TeamFortressViewport::IsNotepadVisible( void )
{
if (m_pNotepad)
return m_pNotepad->isVisible();
return false;
}
void TeamFortressViewport::CreateNotepad()
{
// Create the panel
m_pNotepad = new CNotepad(100, false, 0, 0, ScreenWidth, ScreenHeight);
m_pNotepad->setParent( this );
m_pNotepad->setVisible( false );
}
void TeamFortressViewport::CreateSparePlayerWindow( void )
{
m_pSparePlayerWindow = new CSparePlayerWindow(100, false, 0, 0, ScreenWidth, ScreenHeight);
m_pSparePlayerWindow->setParent( this );
m_pSparePlayerWindow->setVisible( false );
}
//======================================================================================
// CLASS MENU
//======================================================================================
@ -1990,6 +2086,33 @@ int TeamFortressViewport::MsgFunc_VGUIMenu( const char *pszName, int iSize, void
return 1;
}
int TeamFortressViewport::MsgFunc_Notepad( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
char* szText;
int iTitle;
szText = READ_STRING();
iTitle = READ_BYTE();
DisplayNotepad( szText, iTitle );
return 1;
}
int TeamFortressViewport::MsgFunc_SparePlayer( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int iPlayerId;
iPlayerId = READ_BYTE();
ShowSparePlayerWindow();
return 1;
}
int TeamFortressViewport::MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf )
{
if( m_iGotAllMOTD )

View File

@ -575,6 +575,12 @@ public:
void HideScoreBoard( void );
bool IsScoreBoardVisible( void );
void ShowNotepad( void );
bool IsNotepadVisible( void );
void DisplayNotepad( char* szText, int iTitle );
void ShowSparePlayerWindow( void );
bool AllowedToPrintText( void );
void ShowVGUIMenu( int iMenu );
@ -634,6 +640,8 @@ public:
CClassMenuPanel *m_pClassMenu;
ScorePanel *m_pScoreBoard;
SpectatorPanel *m_pSpectatorPanel;
CNotepad *m_pNotepad;
CSparePlayerWindow *m_pSparePlayerWindow;
char m_szServerName[ MAX_SERVERNAME_LENGTH ];
};
@ -1661,6 +1669,48 @@ public:
}
};
class CSparePlayerWindow : public CMenuPanel
{
public:
CTransparentPanel *m_pWindow;
TextPanel *m_pMemo;
Label *m_pTitle;
CImageLabel *m_pImage;
char szText[256];
char szTitle[256];
public:
CSparePlayerWindow(int iTrans, int iRemoveMe, int x,int y,int wide,int tall);
virtual bool SlotInput( int iSlot );
virtual void Open( void );
virtual void Update( void );
virtual void Initialize( void );
};
class CNotepad : public CMenuPanel
{
public:
ScrollPanel *m_pScrollPanel;
CTransparentPanel *m_pNotepadWindow;
TextPanel *m_pBriefing;
CommandButton *m_pCancelButton;
Label *m_pTitle;
CImageLabel *m_pImage;
char szText[256];
char szTitle[256];
public:
CNotepad(int iTrans, int iRemoveMe, int x,int y,int wide,int tall);
virtual bool SlotInput( int iSlot );
virtual void Open( void );
virtual void Update( void );
virtual void Initialize( void );
};
//=========================================================
// Specific Menus to handle old HUD sections
class CHealthPanel : public DragNDropPanel

View File

@ -63,6 +63,7 @@ void VectorAngles( const float *forward, float *angles );
#include "com_model.h"
extern engine_studio_api_t IEngineStudio;
extern void GrabCameraTexture();
/*
The view is allowed to move slightly from it's true position for bobbing,
@ -435,6 +436,15 @@ void V_CalcNormalRefdef( struct ref_params_s *pparams )
// view is the weapon model (only visible from inside body)
view = gEngfuncs.GetViewModel();
//SKY START
//LRC - don't show weapon models when we're drawing the sky.
if (gHUD.m_iCamMode == CAM_ON)
{
savedviewmodel = view->model;
view->model = NULL;
}
//SKY END
// transform the view offset by the model's matrix to get the offset from
// model origin for the view
bob = V_CalcBob( pparams );
@ -780,6 +790,18 @@ void V_CalcNormalRefdef( struct ref_params_s *pparams )
lasttime = pparams->time;
v_origin = pparams->vieworg;
// SKY START
// LRC - override the view position if we're drawing a sky, rather than the player's view
if (gHUD.m_iCamMode == CAM_ON && pparams->nextView == 0)
{
pparams->vieworg[0] = gHUD.m_vecCamPos.x;
pparams->vieworg[1] = gHUD.m_vecCamPos.y;
pparams->vieworg[2] = gHUD.m_vecCamPos.z;
//pparams->viewangles[0]
pparams->nextView = 1;
}
// SKY END
}
void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * finalAngle, float degreesPerSec )

View File

@ -36,9 +36,11 @@
#define BARNEY_AE_SHOOT ( 3 )
#define BARNEY_AE_HOLSTER ( 4 )
#define GUN_GROUP 1
#define BARNEY_BODY_GUNHOLSTERED 0
#define BARNEY_BODY_GUNDRAWN 1
#define BARNEY_BODY_GUNGONE 2
#define BARNEY_BODY_GUNDRAWN 1 * 3 // * 3 for Decay
#define BARNEY_BODY_GUNGONE 2 * 3 // because of LODS
class CBarney : public CTalkMonster
{
@ -406,7 +408,8 @@ void CBarney::Spawn()
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
pev->body = 0; // gun in holster
//pev->body = 0; // gun in holster
SetBodygroup( GUN_GROUP, 0 );
m_fGunDrawn = FALSE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;

View File

@ -156,6 +156,7 @@ void CMultiSource::KeyValue( KeyValueData *pkvd )
}
#define SF_MULTI_INIT 1
#define SF_MULTI_NO_TOGGLE 2
void CMultiSource::Spawn()
{
@ -964,6 +965,7 @@ public:
vec3_t m_start;
vec3_t m_end;
int m_sounds;
string_t m_iszEndLockTarget;
};
TYPEDESCRIPTION CMomentaryRotButton::m_SaveData[] =
@ -974,6 +976,7 @@ TYPEDESCRIPTION CMomentaryRotButton::m_SaveData[] =
DEFINE_FIELD( CMomentaryRotButton, m_start, FIELD_VECTOR ),
DEFINE_FIELD( CMomentaryRotButton, m_end, FIELD_VECTOR ),
DEFINE_FIELD( CMomentaryRotButton, m_sounds, FIELD_INTEGER ),
DEFINE_FIELD( CMomentaryRotButton, m_iszEndLockTarget, FIELD_STRING ),
};
IMPLEMENT_SAVERESTORE( CMomentaryRotButton, CBaseToggle )
@ -1028,6 +1031,11 @@ void CMomentaryRotButton::KeyValue( KeyValueData *pkvd )
m_sounds = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "endlocktarget"))
{
m_iszEndLockTarget = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
CBaseToggle::KeyValue( pkvd );
}
@ -1042,6 +1050,14 @@ void CMomentaryRotButton::PlaySound( void )
// current, not future position.
void CMomentaryRotButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Vyacheslav Dzhura: in Decay there are momentary buttons with MASTER field
if (!UTIL_IsMasterTriggered(m_sMaster, pActivator))
{
// play button locked sound
// PlayLockSounds(pev, &m_ls, TRUE, TRUE);
return;
}
pev->ideal_yaw = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ) / m_flMoveDistance;
UpdateAllButtons( pev->ideal_yaw, 1 );
@ -1092,6 +1108,19 @@ void CMomentaryRotButton::UpdateSelf( float value )
{
pev->avelocity = g_vecZero;
pev->angles = m_end;
// Vyacheslav Dzhura: off the button if we have locked target specified
/* if (!FStringNull( m_iszEndLockTarget ))
{
//CBaseEntity *m_pGoalEnt;
//m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( m_iszEndLockTarget ) );
//if (m_pGoalEnt)
//{
FireTargets(STRING( m_iszEndLockTarget ), this, this, USE_TOGGLE, 0);
SetThink( Off );
//}
}*/
return;
}
else if( m_direction < 0 && value <= 0.0f )
@ -1145,6 +1174,8 @@ void CMomentaryRotButton::Off( void )
}
else
SetThink( NULL );
// if (m_flMoveDistance
}
void CMomentaryRotButton::Return( void )

View File

@ -93,6 +93,8 @@ typedef void(CBaseEntity::*BASEPTR)( void );
typedef void(CBaseEntity::*ENTITYFUNCPTR)( CBaseEntity *pOther );
typedef void(CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
extern BOOL g_startSuit;
// For CLASSIFY
#define CLASS_NONE 0
#define CLASS_MACHINE 1
@ -118,6 +120,7 @@ class CBasePlayerItem;
class CSquadMonster;
#define SF_NORESPAWN ( 1 << 30 )// !!!set this bit on guns and stuff that should never respawn.
#define SF_SPECIFICPLAYER 256 // Decay's flag which indicates that trigger should check player activator's index
//
// EHANDLE. Safe way to point to CBaseEntities who may die between frames
@ -414,7 +417,7 @@ void PlayLockSounds( entvars_t *pev, locksound_t *pls, int flocked, int fbutton
// MultiSouce
//
#define MAX_MULTI_TARGETS 16 // maximum number of targets a single multi_manager entity may be assigned.
#define MAX_MULTI_TARGETS 32 // was 16 - maximum number of targets a single multi_manager entity may be assigned.
#define MS_MAX_TARGETS 32
class CMultiSource : public CPointEntity
@ -523,6 +526,8 @@ public:
Vector m_vecFinalDest;
Vector m_vecFinalAngle;
int m_iPlayerIndex; // Decay's player index
int m_bitsDamageInflict; // DMG_ damage type that the door or tigger does
virtual int Save( CSave &save );
@ -797,5 +802,7 @@ public:
void Spawn( void );
void Precache( void );
void KeyValue( KeyValueData *pkvd );
bool m_bSlaveCoop;
};
#endif

View File

@ -53,6 +53,8 @@ extern cvar_t allow_spectators;
extern cvar_t multibyte_only;
extern int g_teamplay;
BOOL botadded = false;
extern bool bSlaveCoop;
void LinkUserMessages( void );
@ -82,6 +84,43 @@ called when a player connects to a server
*/
BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] )
{
int i;
int count = 0;
// check if this is NOT a bot joining the server...
if (strcmp(pszAddress, "127.0.0.1") != 0)
{
// don't try to add bots for 30 seconds, give client time to get added
bot_check_time = gpGlobals->time + 30.0;
for (i=0; i < 32; i++)
{
if (bot_respawn[i].is_used) // count the number of bots in use
count++;
}
// if there are currently more than the minimum number of bots running
// then kick one of the bots off the server...
if ((min_bots != 0) && (count > min_bots))
{
for (i=0; i < 32; i++)
{
if (bot_respawn[i].is_used) // is this slot used?
{
char cmd[40];
sprintf(cmd, "kick \"%s\"\n", bot_respawn[i].name);
bot_respawn[i].state = BOT_IDLE;
SERVER_COMMAND(cmd); // kick the bot using (kick "name")
break;
}
}
}
}
return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason );
// a client connecting during an intermission can cause problems
@ -690,11 +729,14 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer )
}
else
{
UTIL_LogPrintf( "\"%s<%i><%s><%i>\" changed name to \"%s\"\n",
// TODO: crashes here when changing name during gameplay
UTIL_LogPrintf( "\"%s\" changed name to \"%s\"\n",
//UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n",
STRING( pEntity->v.netname ),
GETPLAYERUSERID( pEntity ),
GETPLAYERAUTHID( pEntity ),
GETPLAYERUSERID( pEntity ),
// GETPLAYERUSERID( pEntity ),
// GETPLAYERAUTHID( pEntity ),
//GETPLAYERUSERID( pEntity ),
// g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ),
g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) );
}
}
@ -947,7 +989,7 @@ const char *GetGameDescription()
if( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized
return g_pGameRules->GetGameDescription();
else
return "Half-Life";
return "Decay";
}
/*

View File

@ -579,6 +579,9 @@ void CBaseMonster::Killed( entvars_t *pevAttacker, int iGib )
// Make sure this condition is fired too (TakeDamage breaks out before this happens on death)
SetConditions( bits_COND_LIGHT_DAMAGE );
// DECAY STATS: tell game rules about killed monster
g_pGameRules->MonsterKilled( pevAttacker, &this->edict()->v );
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner );
if( pOwner )

File diff suppressed because it is too large Load Diff

View File

@ -59,6 +59,7 @@ const char *CBreakable::pSpawnObjects[] =
"weapon_satchel", // 19
"weapon_snark", // 20
"weapon_hornetgun", // 21
"weapon_displacer", // 22
};
void CBreakable::KeyValue( KeyValueData* pkvd )

View File

@ -32,6 +32,7 @@ DLL_GLOBAL CGameRules *g_pGameRules = NULL;
extern DLL_GLOBAL BOOL g_fGameOver;
extern int gmsgDeathMsg; // client dll messages
extern int gmsgMOTD;
extern bool bDecay;
int g_teamplay = 0;

View File

@ -252,6 +252,13 @@ public:
// Teamplay stuff
virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";};
virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget );
// Decay stats
virtual void MonsterKilled( entvars_t *pKiller, entvars_t *pVictim ) {};
virtual void PlayerDamaged( CBasePlayer *pPlayer, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) {};
virtual void BulletsFired( entvars_t *pevAttacker, ULONG cShots, int iBulletType, int iShotId ) {};
virtual void BulletHit( CBaseEntity *pEntity, entvars_t *pevAttacker, int iShotId ) {};
virtual void savePlayerStats( int playerId, int finalGrade, int damageGrade, int killsGrade, int accuracyGrade ) {};
};
//=========================================================
@ -355,6 +362,13 @@ public:
// Immediately end a multiplayer game
virtual void EndMultiplayerGame( void ) { GoToIntermission(); }
// Decay stats
virtual void MonsterKilled( entvars_t *pKiller, entvars_t *pVictim ) {};
virtual void PlayerDamaged( CBasePlayer *pPlayer, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) {};
virtual void BulletsFired( entvars_t *pevAttacker, ULONG cShots, int iBulletType, int iShotId ) {};
virtual void BulletHit( CBaseEntity *pEntity, entvars_t *pevAttacker, int iShotId ) {};
virtual void savePlayerStats( int playerId, int finalGrade, int damageGrade, int killsGrade, int accuracyGrade ) {};
protected:
virtual void ChangeLevel( void );
virtual void GoToIntermission( void );

View File

@ -89,6 +89,7 @@ void CRecharge::Spawn()
pev->solid = SOLID_BSP;
pev->movetype = MOVETYPE_PUSH;
pev->skin = CHARGER_ACTIVE;
UTIL_SetOrigin( pev, pev->origin ); // set size and link into world
UTIL_SetSize( pev, pev->mins, pev->maxs );
@ -192,3 +193,474 @@ void CRecharge::Off( void )
else
SetThink( &CBaseEntity::SUB_DoNothing );
}
//
// NEW MODEL WALL HEV CHARGER AS SEEN IN PLAYSTATION(R)2 VERSION OF HALF-LIFE
//
//-------------------------------------------------------------
// Wall mounted HEV charger
//-------------------------------------------------------------
#define seqCharge_Still 0
#define seqCharge_Deploy 1
#define seqCharge_RetractArm 2
#define seqCharge_GiveShot 3
#define seqCharge_RetractShot 4
#define seqCharge_PrepShot 5
#define seqCharge_ShotIdle 6
#define seqCharge_Inactive 0
#define CHARGER_AWAKE_DISTANCE 64
class CMdlChargerGlass : public CActAnimating
{
public:
void Spawn( );
void Precache( void );
static CMdlChargerGlass *CreateChargerGlass( edict_t *pOwner, const Vector &position );
};
LINK_ENTITY_TO_CLASS( item_rechargeglass, CMdlChargerGlass );
CMdlChargerGlass *CMdlChargerGlass::CreateChargerGlass( edict_t *pOwner, const Vector &position )
{
CMdlChargerGlass *pGlass = GetClassPtr( (CMdlChargerGlass *)NULL );
pGlass->pev->classname = MAKE_STRING( "item_rechargeglass" );
pGlass->pev->origin = position;
pGlass->pev->owner = pOwner;
pGlass->Spawn();
return pGlass;
}
void CMdlChargerGlass::Precache()
{
PRECACHE_MODEL("models/hev_glass.mdl" );
}
void CMdlChargerGlass::Spawn()
{
Precache( );
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
UTIL_SetSize(pev, pev->mins, pev->maxs);
SET_MODEL(ENT(pev), "models/hev_glass.mdl" );
pev->rendermode = kRenderTransTexture;
pev->renderamt = 192;
}
class CMdlCharger : public CActAnimating
{
public:
void Spawn( );
void Precache( void );
void EXPORT Off(void);
void EXPORT Recharge(void);
void EXPORT ChargerThink( void );
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return (CActAnimating :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
void UpdateArm();
void UpdateFluidTank();
void TurnOff();
static TYPEDESCRIPTION m_SaveData[];
float m_flNextCharge, m_flStopCharge;
int m_iReactivate ; // DeathMatch Delay until reactvated
int m_iJuice;
int m_iOn; // 0 = off, 1 = startup, 2 = going
float m_flSoundTime;
float m_flDegree;
bool m_bStartUsing;
int m_iRotValue;
CBaseEntity *pEntity;
CMdlChargerGlass *pGlass;
CBeam *m_pBeam;
};
TYPEDESCRIPTION CMdlCharger::m_SaveData[] =
{
DEFINE_FIELD( CMdlCharger, m_flNextCharge, FIELD_TIME),
DEFINE_FIELD( CMdlCharger, m_flStopCharge, FIELD_TIME),
DEFINE_FIELD( CMdlCharger, m_iReactivate, FIELD_INTEGER),
DEFINE_FIELD( CMdlCharger, m_iJuice, FIELD_INTEGER),
DEFINE_FIELD( CMdlCharger, m_iOn, FIELD_INTEGER),
DEFINE_FIELD( CMdlCharger, m_iRotValue, FIELD_INTEGER ),
DEFINE_FIELD( CMdlCharger, m_flSoundTime, FIELD_TIME),
DEFINE_FIELD( CMdlCharger, m_flDegree, FIELD_TIME),
DEFINE_FIELD( CMdlCharger, m_bStartUsing, FIELD_BOOLEAN),
DEFINE_FIELD( CMdlCharger, pGlass, FIELD_CLASSPTR ),
DEFINE_FIELD( CMdlCharger, pEntity, FIELD_CLASSPTR ),
};
//FIXED: caused bugs after load because of incorrectly specified derivied class
IMPLEMENT_SAVERESTORE( CMdlCharger, CActAnimating );
LINK_ENTITY_TO_CLASS(item_recharge, CMdlCharger);
void CMdlCharger::KeyValue( KeyValueData *pkvd )
{
if ( FStrEq(pkvd->szKeyName, "style") ||
FStrEq(pkvd->szKeyName, "height") ||
FStrEq(pkvd->szKeyName, "value1") ||
FStrEq(pkvd->szKeyName, "value2") ||
FStrEq(pkvd->szKeyName, "value3"))
{
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "dmdelay"))
{
m_iReactivate = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CActAnimating::KeyValue( pkvd );
}
void CMdlCharger::Spawn()
{
Precache( );
pev->solid = SOLID_BBOX; //BBOX;
pev->movetype = MOVETYPE_NONE; //NONE; //PUSH;
// UTIL_SetSize( pev, Vector(-7,-6,-27), Vector(7,6,27) ); //size(-20 -6 -27,20 6 27)
UTIL_SetOrigin(pev, pev->origin); // set size and link into world
UTIL_SetSize(pev, pev->mins, pev->maxs);
SET_MODEL(ENT(pev), "models/hev.mdl" );
m_iJuice = gSkillData.suitchargerCapacity;
pev->frame = 0;
InitBoneControllers();
m_pBeam = CBeam::BeamCreate("sprites/lgtning.spr", 200);
m_pBeam->EntsInit( entindex( ), entindex( ) );
m_pBeam->SetStartAttachment( 3 ); // 2
m_pBeam->SetEndAttachment( 4 ); // 3
m_pBeam->SetColor( 0, 255, 0 );
m_pBeam->SetNoise( 10 );
m_pBeam->SetBrightness( 150 );
m_pBeam->SetWidth( 5 );
m_pBeam->SetScrollRate( 35 );
pGlass = CMdlChargerGlass::CreateChargerGlass(edict(), pev->origin);
pGlass->pev->angles = pev->angles;
int YVal = pev->angles.y;
switch (YVal)
{
case 180:
m_iRotValue = 0;
break;
case 270:
m_iRotValue = -90;
break;
case 0:
m_iRotValue = -180;
break;
case 90:
m_iRotValue = -270;
break;
}
// controller is -90...90
// -90...90 - ang 180 use 0
// 0..180 - ang 270 use -90
// 90..270 - ang 0 use -180
// 180..360 - ang 90 use -270
SetSequence( seqCharge_Inactive );
SetThink(ChargerThink);
if (g_pGameRules->IsCoOp() )
{
CDecayRules *g_pDecayRules;
g_pDecayRules = (CDecayRules*)g_pGameRules;
if ( g_pDecayRules->m_bAlienMode == true )
{
SetThink( NULL );
SetUse( NULL );
}
}
pev->nextthink = gpGlobals->time + 0.1;
}
void CMdlCharger::Precache()
{
PRECACHE_SOUND("items/suitcharge1.wav");
PRECACHE_SOUND("items/suitchargeno1.wav");
PRECACHE_SOUND("items/suitchargeok1.wav");
PRECACHE_MODEL("models/hev.mdl");
UTIL_PrecacheOther("item_rechargeglass");
}
void CMdlCharger::UpdateFluidTank( void )
{
// controllers 1 and 2 - 0..360
m_flDegree += 7;
if (m_flDegree > 360 )
m_flDegree = m_flDegree - 360;
SetBoneController( 1, m_flDegree );
SetBoneController( 2, -m_flDegree );
}
void CMdlCharger::ChargerThink( void )
{
//ALERT( at_console, "seq %d, on %d, juice %d\n", GetSequence(), m_iOn, m_iJuice );
StudioFrameAdvance();
pev->nextthink = gpGlobals->time + 0.1;
float flDist;
if (m_bStartUsing == true)
if (m_flStopCharge >= gpGlobals->time)
{
SetSequence( seqCharge_RetractShot );
//pFluidTank->SetSequence( seqCharge_ToRest );
m_flStopCharge = 0;
}
switch( GetSequence() )
{
case seqCharge_Inactive: // inactive
{
if (pev->skin == CHARGER_EMPTY) // we're in "off" state
{
SetThink( NULL );
return;
}
// iterate on all entities in the vicinity.
CBaseEntity *pTmpEntity = NULL;
while ((pTmpEntity = UTIL_FindEntityInSphere( pTmpEntity, pev->origin, CHARGER_AWAKE_DISTANCE )) != NULL)
{
if (pTmpEntity->IsPlayer())
{
pEntity = pTmpEntity;
if (( pev->origin - pEntity->pev->origin).Length() <= CHARGER_AWAKE_DISTANCE )
{
SetSequence( seqCharge_Deploy );
break;
}
}
}
}
break;
case seqCharge_Deploy: // arm awakens
UpdateArm();
if ( m_fSequenceFinished )
SetSequence( seqCharge_PrepShot );
break;
case seqCharge_PrepShot: // we are waiting for player to use charger
flDist = ( pev->origin - pEntity->pev->origin).Length();
//ALERT( at_console, "dist = %f\n", flDist );
if ( flDist > CHARGER_AWAKE_DISTANCE )
{
SetSequence( seqCharge_RetractArm );
break;
}
UpdateArm();
// can be interruped from USE function which activates seqCharge_GiveShot
break;
case seqCharge_RetractArm:
if ( m_fSequenceFinished )
{
SetSequence( seqCharge_Inactive );
pEntity = NULL;
} else
UpdateArm(); // possible fix???
break;
case seqCharge_RetractShot: // stopped using
m_bStartUsing = false;
if ( m_fSequenceFinished )
SetSequence( seqCharge_PrepShot );
break;
case seqCharge_GiveShot: // started using
m_bStartUsing = false;
if ( m_fSequenceFinished )
{
m_bStartUsing = true;
SetSequence( seqCharge_ShotIdle );
}
break;
case seqCharge_ShotIdle: // in use
// give health here while USE is pressed
break;
default:
break;
}
}
void CMdlCharger::UpdateArm()
{
if ( FNullEnt( pEntity->pev ) )
return;
Vector vecTarget = (pev->origin - pEntity->pev->origin).Normalize( ); // TODO: CRASH HERE, because pEntity is NULL (0x00)
Vector angles = UTIL_VecToAngles (vecTarget);
//ALERT( at_console, "angles = %f, %f, %f - %f\n", angles.x, angles.y, angles.z, angles.y / 180 );
if (angles.y > 180)
angles.y = angles.y - 360;
if (angles.y < -180)
angles.y = angles.y + 360;
// 180 - 100
// 90 - X (50)
// 50 = 90 * 100 / 180
// percent = desired degree * 100 / 180
// percent = desired degree / 180
// controller is -90...90
// -90...90 - 180 use 0
// 0..180 - 270 use -90
// 90..270 - 0 use -180
// 180..360(0) - 90 use
// pos = (end - start) * scalar + start
// pos = 180 * scalar - 90
SetBoneController(3, angles.y + m_iRotValue); //- 90); // +25 to the right
}
void CMdlCharger::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Make sure that we have a caller
if (!pActivator)
return;
// if it's not a player, ignore
if ( !pActivator->IsPlayer() )
return;
if (pev->skin == CHARGER_EMPTY) // already off
return;
// if there is no juice left, turn it off
if (m_iJuice <= 0)
{
TurnOff();
return;
}
// if the player doesn't have the suit, or there is no juice left, make the deny noise
if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<<WEAPON_SUIT))))
{
if (m_flSoundTime <= gpGlobals->time)
{
m_flSoundTime = gpGlobals->time + 0.62;
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM );
}
return;
}
//pFluidTank->StartUse();
pev->nextthink = gpGlobals->time + 0.25; // pev->ltime
SetThink(Off);
// start the give shot sequence and do not use until it's finished
if (GetSequence() != seqCharge_GiveShot)
if ( m_bStartUsing == false )
{
//if ( GetSequence() != seqCharge_PrepShot )
// return; // can't start using until arm fully deployed from charger
SetSequence( seqCharge_GiveShot );
return;
}
// Time to recharge yet?
if (m_flNextCharge >= gpGlobals->time)
return;
// Play the on sound or the looping charging sound
if (!m_iOn)
{
m_iOn++;
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM );
m_flSoundTime = 0.56 + gpGlobals->time;
}
if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time))
{
m_iOn++;
EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/suitcharge1.wav", 0.85, ATTN_NORM );
}
// charge the player
if (pActivator->pev->armorvalue < 100)
{
m_iJuice--;
pActivator->pev->armorvalue += 1;
//pFluidTank->StartUse();
if (pActivator->pev->armorvalue > 100)
pActivator->pev->armorvalue = 100;
}
UpdateFluidTank();
// govern the rate of charge
m_flNextCharge = gpGlobals->time + 0.1;
}
void CMdlCharger::Recharge(void)
{
//if (pev->skin == CHARGER_EMPTY)
// return;
//EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM );
m_iJuice = gSkillData.suitchargerCapacity;
pev->skin = CHARGER_ACTIVE; // set the active skin
SetThink( ChargerThink );
}
void CMdlCharger::Off(void)
{
m_flStopCharge = gpGlobals->time + 0.25;
SetThink( ChargerThink );
pev->nextthink = gpGlobals->time + 0.01;
// Stop looping sound.
if (m_iOn > 1)
STOP_SOUND( ENT(pev), CHAN_STATIC, "items/suitcharge1.wav" );
m_iOn = 0;
if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) )
{
pev->nextthink = pev->ltime + m_iReactivate;
SetThink( Recharge );
}
//else
// SetThink( SUB_DoNothing );
SetSequence( seqCharge_RetractShot );
}
void CMdlCharger::TurnOff(void)
{
pev->skin = CHARGER_EMPTY;
UTIL_Remove( m_pBeam );
m_pBeam = NULL;
SetUse( NULL );
SetSequence( seqCharge_RetractArm );
}

View File

@ -252,3 +252,509 @@ void CWallHealth::Off( void )
else
SetThink( &CBaseEntity::SUB_DoNothing );
}
//
// NEW MODEL WALL HEALTH AS SEEN IN PLAYSTATION(R)2 VERSION OF HALF-LIFE
//
//-------------------------------------------------------------
// Wall mounted health kit
//-------------------------------------------------------------
#define seq_Still 0
#define seq_Deploy 1
#define seq_RetractArm 2
#define seq_GiveShot 3
#define seq_RetractShot 4
#define seq_PrepShot 5
#define seq_ShotIdle 6
#define seq_Inactive 7
#define seq_Slosh 1
#define seq_ToRest 2
#define CHARGER_AWAKE_DISTANCE 64
class CMdlWallHealthTank : public CActAnimating
{
public:
void Spawn( );
void Precache( void );
void Update( int m_iJuice );
void EXPORT TankThink( void );
void StartUse( void );
int m_iJuice;
static CMdlWallHealthTank *CreateFluidTank( edict_t *pOwner, const Vector &position );
};
LINK_ENTITY_TO_CLASS( item_healthchargertank, CMdlWallHealthTank );
CMdlWallHealthTank *CMdlWallHealthTank::CreateFluidTank( edict_t *pOwner, const Vector &position )
{
CMdlWallHealthTank *pHealthTank = GetClassPtr( (CMdlWallHealthTank *)NULL );
pHealthTank->pev->classname = MAKE_STRING( "item_healthchargertank" );
pHealthTank->pev->origin = position;
pHealthTank->pev->owner = pOwner;
pHealthTank->Spawn();
return pHealthTank;
}
void CMdlWallHealthTank::Precache()
{
PRECACHE_MODEL("models/health_charger_both.mdl" );
}
void CMdlWallHealthTank::Spawn()
{
Precache( );
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
UTIL_SetSize(pev, pev->mins, pev->maxs);
SET_MODEL(ENT(pev), "models/health_charger_both.mdl" );
pev->rendermode = kRenderTransTexture;
pev->renderamt = 192;
SetBoneController( 0, 0 ); // -11 to 0 (empty to full)
SetSequence( seq_Still );
SetThink( TankThink );
if (g_pGameRules->IsCoOp() )
{
CDecayRules *g_pDecayRules;
g_pDecayRules = (CDecayRules*)g_pGameRules;
if ( g_pDecayRules->m_bAlienMode == true )
{
SetThink( NULL );
SetUse( NULL );
}
}
pev->nextthink = gpGlobals->time + 0.1;
}
void CMdlWallHealthTank::Update(int m_iJuice)
{
SetBoneController( 0, -(10 - (m_iJuice / gSkillData.healthchargerCapacity * 10)) ); // -11 to 0 (empty to full)
}
void CMdlWallHealthTank::StartUse()
{
if (GetSequence() != seq_Slosh )
SetSequence( seq_Slosh );
}
void CMdlWallHealthTank::TankThink()
{
StudioFrameAdvance();
pev->nextthink = gpGlobals->time + 0.1;
switch( GetSequence() )
{
case seq_Still: // 0 - still
break;
case seq_Slosh: // 1 - slosh
if ( m_fSequenceFinished )
SetSequence( seq_Slosh );
break;
case seq_ToRest: // 2 - to rest
if ( m_fSequenceFinished )
SetSequence( seq_Still );
break;
default:
break;
}
}
#define HEALTHSTATION_FULL 0
#define HEALTHSTATION_EMPTY 1
class CMdlWallHealth : public CActAnimating
{
public:
void Spawn( );
void Precache( void );
void EXPORT Off(void);
void EXPORT Recharge(void);
void EXPORT ChargerThink( void );
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return (CActAnimating :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
void UpdateArm();
void UpdateFluidTank();
void TurnOff();
static TYPEDESCRIPTION m_SaveData[];
float m_flNextCharge, m_flStopCharge;
int m_iReactivate ; // DeathMatch Delay until reactvated
int m_iJuice;
int m_iOn; // 0 = off, 1 = startup, 2 = going
float m_flSoundTime;
bool m_bStartUsing;
int m_iRotValue;
CBaseEntity *pEntity;
CMdlWallHealthTank *pFluidTank;
};
TYPEDESCRIPTION CMdlWallHealth::m_SaveData[] =
{
DEFINE_FIELD( CMdlWallHealth, m_flNextCharge, FIELD_TIME),
DEFINE_FIELD( CMdlWallHealth, m_flStopCharge, FIELD_TIME),
DEFINE_FIELD( CMdlWallHealth, m_iReactivate, FIELD_INTEGER),
DEFINE_FIELD( CMdlWallHealth, m_iJuice, FIELD_INTEGER),
DEFINE_FIELD( CMdlWallHealth, m_iOn, FIELD_INTEGER),
DEFINE_FIELD( CMdlWallHealth, m_iRotValue, FIELD_INTEGER ),
DEFINE_FIELD( CMdlWallHealth, m_flSoundTime, FIELD_TIME),
DEFINE_FIELD( CMdlWallHealth, m_bStartUsing, FIELD_BOOLEAN),
DEFINE_FIELD( CMdlWallHealth, pFluidTank, FIELD_CLASSPTR ),
DEFINE_FIELD( CMdlWallHealth, pEntity, FIELD_CLASSPTR ),
};
//FIXED: caused bugs after load because of incorrectly specified derivied class
IMPLEMENT_SAVERESTORE( CMdlWallHealth, CActAnimating );
LINK_ENTITY_TO_CLASS(item_healthcharger, CMdlWallHealth);
void CMdlWallHealth::KeyValue( KeyValueData *pkvd )
{
if ( FStrEq(pkvd->szKeyName, "style") ||
FStrEq(pkvd->szKeyName, "height") ||
FStrEq(pkvd->szKeyName, "value1") ||
FStrEq(pkvd->szKeyName, "value2") ||
FStrEq(pkvd->szKeyName, "value3"))
{
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "dmdelay"))
{
m_iReactivate = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CActAnimating::KeyValue( pkvd );
}
void CMdlWallHealth::Spawn()
{
Precache( );
pev->solid = SOLID_BBOX;
pev->movetype = MOVETYPE_NONE; //PUSH;
// UTIL_SetSize( pev, Vector(-7,-6,-27), Vector(7,6,27) ); //size(-20 -6 -27,20 6 27)
UTIL_SetOrigin(pev, pev->origin); // set size and link into world
UTIL_SetSize(pev, pev->mins, pev->maxs);
SET_MODEL(ENT(pev), "models/health_charger_body.mdl" );
m_iJuice = gSkillData.healthchargerCapacity;
pev->frame = 0;
pev->skin = HEALTHSTATION_FULL;
InitBoneControllers();
pFluidTank = CMdlWallHealthTank::CreateFluidTank( edict(), pev->origin);
//pFluidTank->pev->origin = pev->origin;
pFluidTank->pev->angles = pev->angles;
int YVal = pev->angles.y;
switch (YVal)
{
case 180:
m_iRotValue = 0;
break;
case 270:
m_iRotValue = -90;
break;
case 0:
m_iRotValue = -180;
break;
case 90:
m_iRotValue = -270;
break;
}
// controller is -90...90
// -90...90 - ang 180 use 0
// 0..180 - ang 270 use -90
// 90..270 - ang 0 use -180
// 180..360 - ang 90 use -270
SetSequence( seq_Inactive );
SetThink(ChargerThink);
pev->nextthink = gpGlobals->time + 0.1;
}
void CMdlWallHealth::Precache()
{
PRECACHE_SOUND("items/medshot4.wav");
PRECACHE_SOUND("items/medshotno1.wav");
PRECACHE_SOUND("items/medcharge4.wav");
PRECACHE_MODEL("models/health_charger_body.mdl" );
UTIL_PrecacheOther("item_healthchargertank");
}
void CMdlWallHealth::UpdateFluidTank( void )
{
pFluidTank->Update( m_iJuice );
/*
-11 - 0
0 - 100
m_iJuice - X
gSkillData.healthchargerCapacity - 100
25 - 50 (?)
50 - 100
25:50*100
m_iJuice div gSkillData.healthchargerCapacity * 100
-(10 - (m_iJuice div gSkillData.healthchargerCapacity * 10))
*/
}
void CMdlWallHealth::ChargerThink( void )
{
//ALERT( at_console, "WallHealth thinks!\n" );
//ALERT( at_console, "next = %f prev = %f\n", m_flNextCharge, m_flStopCharge );
//ALERT( at_console, "seq %d, on %d, juice %d\n", GetSequence(), m_iOn, m_iJuice );
StudioFrameAdvance();
pev->nextthink = gpGlobals->time + 0.1;
Vector posGun, angGun;
Vector vecTarget, vecOut, angles;
float flDist;
if (m_bStartUsing == true)
if (m_flStopCharge >= gpGlobals->time)
{
SetSequence( seq_RetractShot );
pFluidTank->SetSequence( seq_ToRest );
m_flStopCharge = 0;
}
switch( GetSequence() )
{
case seq_Inactive: // inactive
{
if (pev->skin == HEALTHSTATION_EMPTY) // we're in "off" state
{
SetThink( NULL );
return;
}
// iterate on all entities in the vicinity.
CBaseEntity *pTmpEntity = NULL;
while ((pTmpEntity = UTIL_FindEntityInSphere( pTmpEntity, pev->origin, CHARGER_AWAKE_DISTANCE )) != NULL)
{
if (pTmpEntity->IsPlayer())
{
pEntity = pTmpEntity;
if (( pev->origin - pEntity->pev->origin).Length() <= CHARGER_AWAKE_DISTANCE )
{
SetSequence( seq_Deploy );
break;
}
}
}
}
break;
case seq_Deploy: // arm awakens
UpdateArm();
if ( m_fSequenceFinished )
SetSequence( seq_PrepShot );
break;
case seq_PrepShot: // we are waiting for player to use charger
flDist = ( pev->origin - pEntity->pev->origin).Length(); // CRASH IS HERE!!!!!!
//ALERT( at_console, "dist = %f\n", flDist );
if ( flDist > CHARGER_AWAKE_DISTANCE )
{
SetSequence( seq_RetractArm );
break;
}
UpdateArm();
// can be interruped from USE function which activates seq_GiveShot
break;
case seq_RetractArm:
if ( m_fSequenceFinished )
{
SetSequence( seq_Inactive );
pEntity = NULL;
} else
UpdateArm(); // possible fix???
break;
case seq_RetractShot: // stopped using
m_bStartUsing = false;
if ( m_fSequenceFinished )
SetSequence( seq_PrepShot );
break;
case seq_GiveShot: // started using
m_bStartUsing = false;
if ( m_fSequenceFinished )
{
m_bStartUsing = true;
SetSequence( seq_ShotIdle );
}
break;
case seq_ShotIdle: // in use
// give health here while USE is pressed
break;
default:
break;
}
}
void CMdlWallHealth::UpdateArm()
{
Vector vecTarget = (pev->origin - pEntity->pev->origin).Normalize( );
Vector angles = UTIL_VecToAngles (vecTarget);
//ALERT( at_console, "angles = %f, %f, %f - %f\n", angles.x, angles.y, angles.z, angles.y / 180 );
if (angles.y > 180)
angles.y = angles.y - 360;
if (angles.y < -180)
angles.y = angles.y + 360;
// 180 - 100
// 90 - X (50)
// 50 = 90 * 100 / 180
// percent = desired degree * 100 / 180
// percent = desired degree / 180
// controller is -90...90
// -90...90 - 180 use 0
// 0..180 - 270 use -90
// 90..270 - 0 use -180
// 180..360(0) - 90 use
// pos = (end - start) * scalar + start
// pos = 180 * scalar - 90
SetBoneController(0, angles.y + m_iRotValue); //- 90); // +25 to the right
}
void CMdlWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Make sure that we have a caller
if (!pActivator)
return;
// if it's not a player, ignore
if ( !pActivator->IsPlayer() )
return;
if (pev->skin == HEALTHSTATION_EMPTY) // already off
return;
// if there is no juice left, turn it off
if (m_iJuice <= 0)
{
TurnOff(); // do we need it there or in Off() ?
return;
}
// if the player doesn't have the suit, or there is no juice left, make the deny noise
if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<<WEAPON_SUIT))))
{
if (m_flSoundTime <= gpGlobals->time)
{
m_flSoundTime = gpGlobals->time + 0.62;
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshotno1.wav", 1.0, ATTN_NORM );
}
return;
}
pFluidTank->StartUse();
pev->nextthink = gpGlobals->time + 0.25; // pev->ltime
SetThink(Off);
// start the give shot sequence and do not use until it's finished
if (GetSequence() != seq_GiveShot)
if ( m_bStartUsing == false )
{
SetSequence( seq_GiveShot );
return;
}
// Time to recharge yet?
if (m_flNextCharge >= gpGlobals->time)
return;
// Play the on sound or the looping charging sound
if (!m_iOn)
{
m_iOn++;
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM );
m_flSoundTime = 0.56 + gpGlobals->time;
}
if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time))
{
m_iOn++;
EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/medcharge4.wav", 1.0, ATTN_NORM );
}
// charge the player
if ( pActivator->TakeHealth( 1, DMG_GENERIC ) )
{
m_iJuice--;
//pFluidTank->StartUse();
}
UpdateFluidTank();
// govern the rate of charge
m_flNextCharge = gpGlobals->time + 0.1;
}
void CMdlWallHealth::Recharge(void)
{
//if (pev->skin == HEALTHSTATION_EMPTY)
// return;
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM );
m_iJuice = gSkillData.healthchargerCapacity;
pev->skin = HEALTHSTATION_FULL; // set the active skin
SetThink( ChargerThink );
}
void CMdlWallHealth::Off(void)
{
m_flStopCharge = gpGlobals->time + 0.25;
SetThink( ChargerThink );
pev->nextthink = gpGlobals->time + 0.01;
// Stop looping sound.
if (m_iOn > 1)
STOP_SOUND( ENT(pev), CHAN_STATIC, "items/medcharge4.wav" );
m_iOn = 0;
if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) )
{
pev->nextthink = pev->ltime + m_iReactivate;
SetThink(Recharge);
}
//else
// SetThink( SUB_DoNothing );
}
void CMdlWallHealth::TurnOff( void )
{
pev->skin = HEALTHSTATION_EMPTY;
pFluidTank->SetSequence( seq_ToRest );
SetUse( NULL );
SetSequence( seq_RetractArm );
}

View File

@ -53,7 +53,7 @@ extern DLL_GLOBAL int g_iSkillLevel;
#define GRUNT_ATTN ATTN_NORM // attenutation of grunt sentences
#define HGRUNT_LIMP_HEALTH 20
#define HGRUNT_DMG_HEADSHOT ( DMG_BULLET | DMG_CLUB ) // damage types that can kill a grunt with a single headshot.
#define HGRUNT_NUM_HEADS 2 // how many grunt heads are there?
#define HGRUNT_NUM_HEADS 4 // how many grunt heads are there?
#define HGRUNT_MINIMUM_HEADSHOT_DAMAGE 15 // must do at least this much damage in one shot to head to score a headshot kill
#define HGRUNT_SENTENCE_VOLUME (float)0.35 // volume of grunt sentences
@ -62,15 +62,18 @@ extern DLL_GLOBAL int g_iSkillLevel;
#define HGRUNT_GRENADELAUNCHER ( 1 << 2)
#define HGRUNT_SHOTGUN ( 1 << 3)
#define LODS_GROUP 0
#define HEAD_GROUP 1
#define HEAD_GRUNT 0
#define HEAD_COMMANDER 1
#define HEAD_SHOTGUN 2
#define HEAD_M203 3
#define GUN_GROUP 2
#define HEAD_GRUNT 0
#define HEAD_COMMANDER 1// * 3
#define HEAD_SHOTGUN 2// * 3
#define HEAD_M203 3// * 3
#define GUN_MP5 0
#define GUN_SHOTGUN 1
#define GUN_NONE 2
#define GUN_SHOTGUN 1// * 3
#define GUN_NONE 2// * 3
//=========================================================
// Monster's Anim Events Go Here

View File

@ -28,6 +28,15 @@
#include "skill.h"
#include "items.h"
#include "gamerules.h"
#include "decals.h"
#include "actanimating.h"
#define seqEmitterClosed 0
#define seqEmitterDeploy 1
#define seqEmitterIdleOpen 2
#define seqEmitterBroken1 3
#define seqEmitterBroken2 4
#define seqEmitterDeath 5
extern int gmsgItemPickup;

View File

@ -72,6 +72,8 @@ TYPEDESCRIPTION CMonsterMaker::m_SaveData[] =
DEFINE_FIELD( CMonsterMaker, m_iMaxLiveChildren, FIELD_INTEGER ),
DEFINE_FIELD( CMonsterMaker, m_fActive, FIELD_BOOLEAN ),
DEFINE_FIELD( CMonsterMaker, m_fFadeChildren, FIELD_BOOLEAN ),
DEFINE_FIELD( CMonsterMaker, m_fIsWarpBall, FIELD_BOOLEAN ),
DEFINE_FIELD( CMonsterMaker, m_cTotalMonstersCount, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE( CMonsterMaker, CBaseMonster )
@ -93,14 +95,33 @@ void CMonsterMaker::KeyValue( KeyValueData *pkvd )
m_iszMonsterClassname = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "warptarget") || FStrEq(pkvd->szKeyName, "makertarget") || FStrEq(pkvd->szKeyName, "warp_target") )
{
m_iszWarpTarget = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "monsterspawnflags") ) // monsterspawnflags
{
m_iChildrenSpawnflags = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
// radius
// damage_delay
else
CBaseMonster::KeyValue( pkvd );
}
void CMonsterMaker::Spawn()
{
//ALERT( at_console, "CMonsterMaker::Spawn\n");
m_fIsWarpBall = !strcmp(STRING(pev->classname), "env_warpball");
pev->solid = SOLID_NOT;
// for WarpBall to function correctly - it's spawnflag is another then same in monstermaker
if ( m_fIsWarpBall && FBitSet ( pev->spawnflags, SF_WARPBALL_ONCE )) // flag bit 1
SetBits ( pev->spawnflags, SF_MONSTERMAKER_FIREONCE ); // flag bit 16
m_cLiveChildren = 0;
Precache();
if( !FStringNull( pev->targetname ) )
@ -149,9 +170,20 @@ void CMonsterMaker::Spawn()
void CMonsterMaker::Precache( void )
{
//ALERT( at_console, "%s::Precache\n", STRING(pev->classname));
CBaseMonster::Precache();
if (m_fIsWarpBall)
{
m_flDelay = 5;
UTIL_PrecacheOther( "effect_warpball" );
}
if (FStringNull( m_iszMonsterClassname ) != true)
UTIL_PrecacheOther( STRING( m_iszMonsterClassname ) );
else
ALERT( at_console, "CMonsterMaker without a children name!\n");
}
//=========================================================
@ -206,8 +238,9 @@ void CMonsterMaker::MakeMonster( void )
}
pevCreate = VARS( pent );
pevCreate->origin = pev->origin;
pevCreate->angles = pev->angles;
pevCreate->origin = DesiredOrigin;
pevCreate->angles = DesiredAngles;
pevCreate->spawnflags = m_iChildrenSpawnflags;
SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND );
// Children hit monsterclip brushes
@ -228,10 +261,21 @@ void CMonsterMaker::MakeMonster( void )
if( m_cNumMonsters == 0 )
{
// Disable this forever. Don't kill it because it still gets death notices
// FIXME: do we need this comment? "Disable this forever. Don't kill it because it still gets death notices"
//m_cNumMonsters = m_cTotalMonstersCount;
//m_fActive = FALSE;
SetThink( NULL );
SetUse( NULL );
}
if ( !FBitSet ( pev->spawnflags, SF_MONSTERMAKER_CYCLIC ) )
{
if ( FBitSet ( pev->spawnflags, SF_MONSTERMAKER_FIREONCE ) )
{
//ALERT( at_console, "Removing MakeMonster\n");
UTIL_Remove( this );
}
}
}
//=========================================================
@ -270,6 +314,8 @@ void CMonsterMaker::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US
//=========================================================
void CMonsterMaker::MakerThink( void )
{
//ALERT( at_console, "CMonsterMaker::MakerThink\n");
pev->nextthink = gpGlobals->time + m_flDelay;
MakeMonster();

View File

@ -67,6 +67,11 @@ extern CGraph WorldGraph;
#define FLASH_DRAIN_TIME 1.2f //100 units/3 minutes
#define FLASH_CHARGE_TIME 0.2f // 100 units/20 seconds (seconds per unit)
#define MODE_STAND 0
#define MODE_RUN 1
#define MODE_CROUCH 2
#define MODE_JUMP 3
// Global Savedata for player
TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] =
{
@ -116,6 +121,7 @@ TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] =
DEFINE_FIELD( CBasePlayer, m_pTank, FIELD_EHANDLE ),
DEFINE_FIELD( CBasePlayer, m_iHideHUD, FIELD_INTEGER ),
DEFINE_FIELD( CBasePlayer, m_iFOV, FIELD_INTEGER ),
DEFINE_FIELD( CBasePlayer, m_iDecayId, FIELD_INTEGER ),
//DEFINE_FIELD( CBasePlayer, m_fDeadTime, FIELD_FLOAT ), // only used in multiplayer games
//DEFINE_FIELD( CBasePlayer, m_fGameHUDInitialized, FIELD_INTEGER ), // only used in multiplayer games
@ -3440,7 +3446,15 @@ void CBasePlayer::ForceClientDllUpdate( void )
m_fInitHUD = TRUE; // Force HUD gmsgResetHUD message
memset( m_rgAmmoLast, 0, sizeof( m_rgAmmoLast )); // a1ba: Force update AmmoX
int gmsgLensFlare = 0;
int gmsgAimFrame = 0;
int gmsgNotepad = 0;
int gmsgChangeMode = 0;
int gmsgCamera = 0;
int gmsgChangePlayer = 0;
int gmsgSparePlayer = 0;
int gmsgAlienState = 0;
int gmsgUpdateDecayPlayerName = 0;
// Now force all the necessary messages
// to be sent.
@ -4363,6 +4377,7 @@ Vector CBasePlayer::GetAutoaimVector( float flDelta )
// ALERT( at_console, "%f %f\n", angles.x, angles.y );
UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim );
//AutoaimFrame(vecSrc, flDist, flDelta); //draw selection frame around objects
return gpGlobals->v_forward;
}
@ -4495,6 +4510,94 @@ void CBasePlayer::ResetAutoaim()
m_fOnTarget = FALSE;
}
void CBasePlayer :: AutoaimFrame( Vector &vecSrc, float flDist, float flDelta )
{
edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 );
CBaseEntity *pEntity;
float bestdot;
Vector bestdir;
TraceResult tr;
MESSAGE_BEGIN( MSG_ALL, gmsgAimFrame);
WRITE_BYTE( 0 );
WRITE_BYTE( 0.0 );
WRITE_COORD( 0.0 );
WRITE_COORD( 0.0 );
WRITE_COORD( 0.0 );
WRITE_COORD( 0.0 );
WRITE_COORD( 0.0 );
WRITE_COORD( 0.0 );
MESSAGE_END();
UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim );
// try all possible entities
bestdot = flDelta; // +- 10 degrees
UTIL_TraceLine( vecSrc, vecSrc + bestdir * flDist, dont_ignore_monsters, edict(), &tr );
for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ )
{
Vector center;
Vector dir;
float dot;
if ( pEdict->free ) // Not in use
continue;
if (pEdict == edict())
continue;
if ( !g_pGameRules->ShouldAutoAim( this, pEdict ) )
continue;
pEntity = Instance( pEdict );
if (pEntity == NULL)
continue;
center = pEntity->BodyTarget( vecSrc );
dir = (center - vecSrc).Normalize( );
// make sure it's in front of the player
if (DotProduct (dir, gpGlobals->v_forward ) < 0)
continue;
dot = fabs( DotProduct (dir, gpGlobals->v_right ) )
+ fabs( DotProduct (dir, gpGlobals->v_up ) ) * 0.5;
// tweek for distance
dot *= 1.0 + 0.2 * ((center - vecSrc).Length() / flDist);
if (dot > bestdot)
continue; // to far to turn
UTIL_TraceLine( vecSrc, center, dont_ignore_monsters, edict(), &tr );
if (tr.flFraction != 1.0 && tr.pHit != pEdict)
{
continue;
}
if (!FClassnameIs(pEntity->pev,"func_frame")) continue;
CFuncFrame* pFrame = (CFuncFrame*)CBaseEntity::Instance(pEdict);
//ALERT( at_console, "Kind is %d\n", pFrame->m_iKind);
if ((vecSrc-center).Length() < 200) //was 50
{
MESSAGE_BEGIN( MSG_ALL, gmsgAimFrame);
WRITE_BYTE( pEntity->entindex() );
WRITE_BYTE( pFrame->m_iKind );
WRITE_COORD( pEntity->pev->mins.x );
WRITE_COORD( pEntity->pev->mins.y );
WRITE_COORD( pEntity->pev->mins.z );
WRITE_COORD( pEntity->pev->maxs.x );
WRITE_COORD( pEntity->pev->maxs.y );
WRITE_COORD( pEntity->pev->maxs.z );
MESSAGE_END();
}
}
}
/*
=============
SetCustomDecalFrames
@ -4713,9 +4816,25 @@ BOOL CBasePlayer::SwitchWeapon( CBasePlayerItem *pWeapon )
return TRUE;
}
//=========================================================
// Set Decay's player index
//=========================================================
void CBasePlayer::SetDecayPlayerIndex( int Id )
{
m_iDecayId = Id;
}
//=========================================================
// Dead HEV suit prop
//=========================================================
#define PLAYER_LODS 4
#define HEAD_GROUP 1
#define HEAD_GORDON 0
#define HEAD_HELMET 1
class CDeadHEV : public CBaseMonster
{
public:
@ -4763,7 +4882,8 @@ void CDeadHEV::Spawn( void )
pev->effects = 0;
pev->yaw_speed = 8;
pev->sequence = 0;
pev->body = 1;
//pev->body = 1;
SetBodygroup( HEAD_GROUP, HEAD_HELMET * PLAYER_LODS );
m_bloodColor = BLOOD_COLOR_RED;
pev->sequence = LookupSequence( m_szPoses[m_iPose] );

View File

@ -226,7 +226,9 @@ public:
virtual int Restore( CRestore &restore );
void RenewItems(void);
void PackDeadPlayerItems( void );
void PackAllItems( void );
void RemoveAllItems( BOOL removeSuit );
void SetDecayPlayerIndex( int Id );
BOOL SwitchWeapon( CBasePlayerItem *pWeapon );
// JOHN: sends custom messages if player HUD data has changed (eg health, ammo)
@ -298,6 +300,7 @@ public:
void ResetAutoaim( void );
Vector GetAutoaimVector( float flDelta );
Vector AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta );
void AutoaimFrame( Vector &vecSrc, float flDist, float flDelta ); // Draw selection frame around objects
void ForceClientDllUpdate( void ); // Forces all client .dll specific data to be resent to client.
@ -325,6 +328,7 @@ public:
void SetPrefsFromUserinfo( char *infobuffer );
float m_flNextChatTime;
int m_iDecayId; // Decay player index
int m_iAutoWepSwitch;

View File

@ -1466,3 +1466,242 @@ int CSittingScientist::FIdleSpeak( void )
CTalkMonster::g_talkWaitTime = 0;
return FALSE;
}
//=========================================================
// Doctor Keller
// monster_wheelchair
//=========================================================
class CWheelChairScientist : public CScientist // kdb: changed from public CBaseMonster so he can speak
{
public:
void Spawn( void );
void Precache( void );
int FIdleSpeak( void );
void PainSound( void );
void TalkInit( void );
BOOL CanHeal( void );
};
LINK_ENTITY_TO_CLASS( monster_wheelchair, CWheelChairScientist );
void CWheelChairScientist :: Spawn( )
{
Precache();
SET_MODEL(ENT(pev), "models/wheelchair_sci.mdl");
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = gSkillData.barneyHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
pev->body = 0; // gun in holster
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
MonsterInit();
SetUse( FollowerUse );
}
void CWheelChairScientist :: Precache( void )
{
PRECACHE_MODEL("models/wheelchair_sci.mdl");
PRECACHE_SOUND("keller/dk_pain1.wav");
PRECACHE_SOUND("keller/dk_pain2.wav");
PRECACHE_SOUND("keller/dk_pain3.wav");
PRECACHE_SOUND("keller/dk_pain4.wav");
PRECACHE_SOUND("keller/dk_pain5.wav");
PRECACHE_SOUND("keller/dk_pain6.wav");
PRECACHE_SOUND("keller/dk_pain7.wav");
PRECACHE_SOUND("wheelchair/wheelchair_jog.wav");
PRECACHE_SOUND("wheelchair/wheelchair_run.wav");
PRECACHE_SOUND("wheelchair/wheelchair_walk.wav");
TalkInit();
CTalkMonster::Precache();
}
int CWheelChairScientist :: FIdleSpeak( void )
{
return -1;
}
BOOL CWheelChairScientist :: CanHeal( void )
{
return FALSE;
}
void CWheelChairScientist :: PainSound( void )
{
if (gpGlobals->time < m_painTime )
return;
m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75);
switch (RANDOM_LONG(0,6))
{
case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "keller/dk_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "keller/dk_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "keller/dk_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 3: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "keller/dk_pain4.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 4: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "keller/dk_pain5.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 5: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "keller/dk_pain6.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 6: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "keller/dk_pain7.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
}
}
void CWheelChairScientist :: TalkInit()
{
CTalkMonster::TalkInit();
// Keller's speach group names (group names are in sentences.txt)
m_szGrp[TLK_ANSWER] = NULL;
m_szGrp[TLK_QUESTION] = NULL;
m_szGrp[TLK_IDLE] = "DK_IDLE";
m_szGrp[TLK_STARE] = "DK_STARE";
m_szGrp[TLK_HELLO] = "DK_HELLO";
m_szGrp[TLK_FEAR] = "DK_FEAR";
m_szGrp[TLK_PLFEAR] = "DK_PLFEAR";
m_szGrp[TLK_HEAL] = NULL;
m_szGrp[TLK_USE] = "DK_OK";
m_szGrp[TLK_UNUSE] = "DK_WAIT";
m_szGrp[TLK_STOP] = "DK_STOP";
m_szGrp[TLK_NOSHOOT] = "DK_SCARED";
m_szGrp[TLK_PLHURT1] = NULL;
m_szGrp[TLK_PLHURT2] = NULL;
m_szGrp[TLK_PLHURT3] = NULL;
m_szGrp[TLK_WOUND] = NULL;
m_szGrp[TLK_MORTAL] = NULL;
// get voice for head
m_voicePitch = 100;
}
//=========================================================
// Doctor Rosenberg
// monster_rosenberg
//=========================================================
class CRosenberg : public CScientist // kdb: changed from public CBaseMonster so he can speak
{
public:
void Spawn( void );
void Precache( void );
void PainSound( void );
void TalkInit( void );
int FIdleSpeak( void );
};
LINK_ENTITY_TO_CLASS( monster_rosenberg, CRosenberg );
void CRosenberg :: Spawn( )
{
Precache();
SET_MODEL(ENT(pev), "models/scientist_rosenberg.mdl");
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = gSkillData.barneyHealth+10;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
SetBodygroup( BODY_GROUP, BODY_LOD0 );
SetBodygroup( HEAD_GROUP, 0 );
MonsterInit();
SetUse( FollowerUse );
}
void CRosenberg :: Precache( void )
{
PRECACHE_MODEL("models/scientist_rosenberg.mdl");
PRECACHE_SOUND("rosenberg/ro_pain0.wav");
PRECACHE_SOUND("rosenberg/ro_pain1.wav");
PRECACHE_SOUND("rosenberg/ro_pain2.wav");
PRECACHE_SOUND("rosenberg/ro_pain3.wav");
PRECACHE_SOUND("rosenberg/ro_pain4.wav");
PRECACHE_SOUND("rosenberg/ro_pain5.wav");
PRECACHE_SOUND("rosenberg/ro_pain6.wav");
PRECACHE_SOUND("rosenberg/ro_pain7.wav");
PRECACHE_SOUND("rosenberg/ro_pain8.wav");
TalkInit();
CTalkMonster::Precache();
}
void CRosenberg :: PainSound( void )
{
if (gpGlobals->time < m_painTime )
return;
m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75);
switch (RANDOM_LONG(0,8))
{
case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain0.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 3: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 4: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain4.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 5: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain5.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 6: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain6.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 7: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain7.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 8: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain8.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
}
}
void CRosenberg :: TalkInit()
{
CTalkMonster::TalkInit();
// Rosenberg's speach group names (group names are in sentences.txt)
m_szGrp[TLK_ANSWER] = NULL;
m_szGrp[TLK_QUESTION] = NULL;
m_szGrp[TLK_IDLE] = NULL;
m_szGrp[TLK_STARE] = NULL;
m_szGrp[TLK_HELLO] = NULL;
m_szGrp[TLK_FEAR] = "RO_FEAR";
m_szGrp[TLK_PLFEAR] = "RO_PLFEAR";
m_szGrp[TLK_HEAL] = "RO_HEAL";
m_szGrp[TLK_USE] = "RO_OK";
m_szGrp[TLK_UNUSE] = "RO_WAIT";
m_szGrp[TLK_STOP] = "RO_STOP";
m_szGrp[TLK_NOSHOOT] = "RO_SCARED";
m_szGrp[TLK_PLHURT1] = "!RO_CUREA";
m_szGrp[TLK_PLHURT2] = "!RO_CUREB";
m_szGrp[TLK_PLHURT3] = "!RO_CUREC";
m_szGrp[TLK_WOUND] = "RO_WOUND";
m_szGrp[TLK_MORTAL] = "RO_MORTAL";
// get voice for head
m_voicePitch = 100;
}
int CRosenberg::FIdleSpeak( void )
{
return -1;
}

View File

@ -342,6 +342,7 @@ TYPEDESCRIPTION CBaseToggle::m_SaveData[] =
DEFINE_FIELD( CBaseToggle, m_vecFinalAngle, FIELD_VECTOR ),
DEFINE_FIELD( CBaseToggle, m_sMaster, FIELD_STRING),
DEFINE_FIELD( CBaseToggle, m_bitsDamageInflict, FIELD_INTEGER ), // damage type inflicted
DEFINE_FIELD( CBaseToggle, m_iPlayerIndex, FIELD_INTEGER ), // Decay's player index
};
IMPLEMENT_SAVERESTORE( CBaseToggle, CBaseAnimating )

View File

@ -56,6 +56,8 @@ const char *CTalkMonster::m_szFriends[TLK_CFRIENDS] =
"monster_barney",
"monster_scientist",
"monster_sitting_scientist",
"monster_rosenberg",
"monster_wheelchair"
};
//=========================================================

View File

@ -38,7 +38,7 @@
#define bit_saidHeard (1<<6)
#define bit_saidSmelled (1<<7)
#define TLK_CFRIENDS 3
#define TLK_CFRIENDS 5
typedef enum
{

View File

@ -33,6 +33,7 @@ extern DLL_GLOBAL BOOL g_fGameOver;
CHalfLifeTeamplay::CHalfLifeTeamplay()
{
ALERT( at_console, "Half-Life multiplayer teamplay\n");
m_DisableDeathMessages = FALSE;
m_DisableDeathPenalty = FALSE;

View File

@ -27,6 +27,10 @@
#include "saverestore.h"
#include "trains.h" // trigger_camera has train functionality
#include "gamerules.h"
#include "shake.h" // trigger_enddecay fading constants
#include "effects.h" // env_render can use instance of CEnvMirroredLaser
#include "triggers.h"
#include "shellapi.h"
#define SF_TRIGGER_PUSH_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF
#define SF_TRIGGER_HURT_TARGETONCE 1// Only fire hurt target once
@ -34,8 +38,14 @@
#define SF_TRIGGER_HURT_NO_CLIENTS 8//spawnflag that makes trigger_push spawn turned OFF
#define SF_TRIGGER_HURT_CLIENTONLYFIRE 16// trigger hurt will only fire its target if it is hurting a client
#define SF_TRIGGER_HURT_CLIENTONLYTOUCH 32// only clients may touch this trigger.
#define SF_MM_KILLTARGETS 2
// to help trigger entites define who is standing inside
#define PF_PLAYER1 1
#define PF_PLAYER2 2
extern DLL_GLOBAL BOOL g_fGameOver;
extern bool bDecay;
extern void SetMovedir(entvars_t* pev);
extern Vector VecBModelOrigin( entvars_t* pevBModel );
@ -457,6 +467,7 @@ void CMultiManager::ManagerReport( void )
#define SF_RENDER_MASKMODE ( 1 << 2 )
#define SF_RENDER_MASKCOLOR ( 1 << 3 )
// TODO: it is rather slow using NETNAME to set renderfx, need to make list of those entities on level load
class CRenderFxManager : public CBaseEntity
{
public:
@ -492,6 +503,38 @@ void CRenderFxManager::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T
if( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) )
pevTarget->rendercolor = pev->rendercolor;
}
} else
if (!FStringNull(pev->netname))
{
edict_t* pentTarget = NULL;
while ( 1 )
{
pentTarget = FIND_ENTITY_BY_NETNAME(pentTarget, STRING(pev->netname));
if (FNullEnt(pentTarget))
break;
// other env_renders also have netname specified, and we must not touch them, so:
// if classname<>env_render then
// do smthng
if (FClassnameIs(pentTarget, "env_render"))
break;
entvars_t *pevTarget = VARS( pentTarget );
if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKFX ) )
pevTarget->renderfx = pev->renderfx;
if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKAMT ) )
pevTarget->renderamt = pev->renderamt;
if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKMODE ) )
pevTarget->rendermode = pev->rendermode;
if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) )
pevTarget->rendercolor = pev->rendercolor;
if (FClassnameIs(pentTarget, "env_mirroredlaser"))
{
CEnvMirroredLaser* pLaser = (CEnvMirroredLaser*)CBaseEntity::Instance(pentTarget);
pLaser->ReColorLasers();
}
}
}
}
@ -552,6 +595,11 @@ void CBaseTrigger::KeyValue( KeyValueData *pkvd )
m_bitsDamageInflict = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "player_index"))
{
m_iPlayerIndex = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseToggle::KeyValue( pkvd );
}
@ -1496,6 +1544,17 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator )
}
//ALERT( at_console, "Level touches %d levels\n", ChangeList( levels, 16 ) );
ALERT( at_console, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot );
/*
Vyacheslav Dzhura: 8/9/2008
DONE: COMMENTED - EXPERIMENTAL!!!!!!!!
*/
if ( g_pGameRules->IsCoOp )
{
char cmd[128];
sprintf( cmd, "changelevel %s %s\n", st_szNextMap, st_szNextSpot );
SERVER_COMMAND( cmd );
} else
CHANGE_LEVEL( st_szNextMap, st_szNextSpot );
}
@ -1962,6 +2021,25 @@ LINK_ENTITY_TO_CLASS( trigger_endsection, CTriggerEndSection )
void CTriggerEndSection::EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
char szFilename[MAX_PATH];
GET_GAME_DIR( szFilename );
strcat( szFilename, "\\manual\\credits.xml" );
char szFilename2[MAX_PATH];
GET_GAME_DIR( szFilename2 );
strcat( szFilename2, "\\manual" );
int i;
for( i = 0; i < strlen( szFilename ); i++)
if ( szFilename[i] == '/' ) szFilename[i] = '\\';
for( i = 0; i < strlen( szFilename2 ); i++)
if ( szFilename2[i] == '/' ) szFilename2[i] = '\\';
if (!IS_DEDICATED_SERVER())
ShellExecute( GetActiveWindow(), "open", "iexplore", szFilename, szFilename2, SW_MAXIMIZE);
// Only save on clients
if( pActivator && !pActivator->IsNetClient() )
return;
@ -2386,3 +2464,592 @@ void CTriggerCamera::Move()
float fraction = 2 * gpGlobals->frametime;
pev->velocity = ( ( pev->movedir * pev->speed ) * fraction ) + ( pev->velocity * ( 1 - fraction ) );
}
//
// TRIGGER_ENDDECAY
//
class CTriggerEndDecay : public CBaseTrigger
{
//private:
// int m_iPhase;
public:
void Spawn( void );
void EXPORT EndDecayTouch( CBaseEntity *pOther );
void KeyValue( KeyValueData *pkvd );
void EXPORT EndDecayUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT EndDecayThink( void );
bool bIsFinal;
bool bUsed;
t_playerStats stats[3];
};
LINK_ENTITY_TO_CLASS( trigger_enddecay, CTriggerEndDecay );
void CTriggerEndDecay::Spawn( void )
{
bUsed = false;
if ( g_pGameRules->IsDeathmatch() )
{
REMOVE_ENTITY( ENT(pev) );
return;
}
InitTrigger();
SetThink( SUB_DoNothing );
SetUse ( EndDecayUse );
// If it is a "use only" trigger, then don't set the touch function.
if ( ! (pev->spawnflags & SF_ENDSECTION_USEONLY) )
SetTouch( EndDecayTouch );
}
/*
MOVED TO: decay_gamerules.cpp
char getGradeChar( int grade )
{
char gradeChar;
switch ( grade )
{
case 3:
gradeChar = 'D';
break;
case 2:
gradeChar = 'C';
break;
case 1:
gradeChar = 'B';
break;
case 0:
gradeChar = 'A';
break;
default:
gradeChar = 'D';
break;
}
return gradeChar;
}
*/
void CTriggerEndDecay::EndDecayUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Only save on clients
//if ( pActivator && !pActivator->IsNetClient() )
// return;
SetUse( NULL );
/*while (pActivator = UTIL_FindEntityByClassname(pActivator, "player"))
{
((CBasePlayer *)((CBaseEntity *)pActivator))->EnableControl(FALSE);
}*/
CBasePlayer *client;
client = NULL;
while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) )
{
if ( !client->pev )
continue;
if ( !(client->IsNetClient()) ) // Not a client ? (should never be true)
continue;
client->EnableControl(FALSE);
}
CDecayRules *g_pDecayRules = (CDecayRules*)g_pGameRules;
// our players should have DecayId of 1 or 2, so "loop" between these two numbers only
if ( this->bIsFinal == true )
{
int damageGrade;
int killsGrade;
int accuracyGrade;
char gradeChar[8];
memset( gradeChar, 0, sizeof( gradeChar ) );
damageGrade = killsGrade = accuracyGrade = 3; // by default "D" to all categories
for (int i = 1; i <= 2; i++ )
{
t_playerStats *curStats = &g_pDecayRules->pStats[i];
// compute accuracy
if ( ( curStats->shots * 100 ) != 0 )
curStats->accuracy = (float)curStats->hits / (float)curStats->shots * 100;
else
curStats->accuracy = 0;
// go through grade values for C,B,A
for (int j = 2; j >= 0; j-- )
{
if ( curStats->damage <= stats[j].damage )
damageGrade = j;
if ( curStats->kills >= stats[j].kills )
killsGrade = j;
if ( curStats->accuracy >= stats[j].accuracy )
accuracyGrade = j;
}
if ( curStats->accuracy == 0 ) // not a single shot!!!
accuracyGrade = 3;
int finalGrade = ( damageGrade + killsGrade + accuracyGrade ) / 3;
g_pDecayRules->savePlayerStats( i, finalGrade, damageGrade, killsGrade, accuracyGrade );
gradeChar[i] = g_pDecayRules->getGradeChar( finalGrade );
}
char buf[256];
sprintf( buf, "Player 1 grade: %c\nPlayer 2 grade: %c", gradeChar[1], gradeChar[2] );
UTIL_ShowMessageAll( buf );
}
UTIL_ScreenFadeAll( Vector(0, 0, 0), 7, 3, 255, FFADE_OUT );
UTIL_ShowMessageAll( STRING(pev->message) );
pev->nextthink = gpGlobals->time + 7;
SetThink( EndDecayThink );
}
void CTriggerEndDecay::EndDecayThink( void )
{
//********************************************************************************
// Theoretically we should go there after level-end dialog which should be called
// from client.dll from EndDecayUse, then player should choose next mission, read
// it's briefing and continue game on that level, or restart current or exit the
// game. Callback is done via console commands which are intercepted in this dll
// in clien.cpp file which then could call methods of this trigger_enddecay
//********************************************************************************
if ( bUsed == true )
return;
/*
if ( pev->spawnflags & 2 )
{
bUsed = true;
return;
}
*/
static char szNextMap[128];
sprintf( szNextMap, "null" );
if (g_pGameRules->IsCoOp())
{
CDecayRules *g_pDecayRules = (CDecayRules*)g_pGameRules;
sprintf( szNextMap, g_pDecayRules->getDecayNextMap() );
}
//if ( pev->message )
// g_engfuncs.pfnEndSection(STRING(pev->message));
bool bHasNextMap = ( strcmp( szNextMap, "null" ) != 0 );
if ( this->bIsFinal )
{
if ( ( bHasNextMap == true ) && ( pev->spawnflags & 2 ) == false )
CHANGE_LEVEL( szNextMap, NULL );
else
{
if ( ( pev->spawnflags & 2 ) == false )
{
if ( pev->message )
g_engfuncs.pfnEndSection(STRING(pev->message));
else
g_engfuncs.pfnEndSection( "Decay" );
} // else map should be ended somehow via it's entities login
}
} else
{
// do restart of server
char cmd[128];
sprintf( cmd, "restart\n" );
SERVER_COMMAND( cmd );
}
/*
if ( ( strcmp( szNextMap, "null" ) != 0 ) && ( this->bIsFinal == true ) )
CHANGE_LEVEL( szNextMap, NULL );
else {
int mapId = g_pDecayRules->getDecayMapId();
if ( ( mapId == 11 ) || ( mapId == 12 ) ) // do not restart server for dy_outro or dy_alien
{
if ( pev->message )
g_engfuncs.pfnEndSection(STRING(pev->message));
else
g_engfuncs.pfnEndSection( "Decay" );
} else
{
// do restart of server
char cmd[128];
sprintf( cmd, "restart\n" );
SERVER_COMMAND( cmd );
}
}
*/
// TODO: send here message to client.dll to popup level stats dialog
// TODO: do we need this here?
// pev->nextthink = gpGlobals->time + 10.0;
// SetThink( SUB_DoNothing );
bUsed = true;
//UTIL_Remove( this );
}
void CTriggerEndDecay::EndDecayTouch( CBaseEntity *pOther )
{
// Only save on clients
if ( !pOther->IsNetClient() )
return;
SetTouch( NULL );
Use( pOther, pOther, USE_ON, 1 );
// same as use below
}
void CTriggerEndDecay :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "success"))
{
if (atoi( pkvd->szValue ) == 1)
this->bIsFinal = true;
else
this->bIsFinal = false;
pkvd->fHandled = TRUE;
} else
//
// WOUNDS (DAMAGE)
//
if (FStrEq(pkvd->szKeyName, "woundsa"))
{
this->stats[0].damage = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
if (FStrEq(pkvd->szKeyName, "woundsb"))
{
this->stats[1].damage = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
if (FStrEq(pkvd->szKeyName, "woundsc"))
{
this->stats[2].damage = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
//
// KILLS
//
if (FStrEq(pkvd->szKeyName, "killsa"))
{
this->stats[0].kills = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
if (FStrEq(pkvd->szKeyName, "killsb"))
{
this->stats[1].kills = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
if (FStrEq(pkvd->szKeyName, "killsc"))
{
this->stats[2].kills = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
//
// ACCURACY
//
if (FStrEq(pkvd->szKeyName, "accuracya"))
{
this->stats[0].accuracy = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
if (FStrEq(pkvd->szKeyName, "accuracyb"))
{
this->stats[1].accuracy = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
if (FStrEq(pkvd->szKeyName, "accuracyc"))
{
this->stats[2].accuracy = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
if (FStrEq(pkvd->szKeyName, "section"))
{
// m_iszSectionName = ALLOC_STRING( pkvd->szValue );
// Store this in message so we don't have to write save/restore for this ent
pev->message = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
CBaseTrigger::KeyValue( pkvd );
}
//
// TRIGGER_PLAYERFREEZE (based on code from Spirit of Half-Life SDK)
//
class CPlayerFreeze: public CBaseDelay
{
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void Think( void );
EHANDLE m_hActivator;
};
void CPlayerFreeze::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
CBasePlayer *client;
client = NULL;
while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) )
{
if ( !client->pev )
continue;
// if ( client->edict() == pEntity )
// continue;
// if ( !(client->IsNetClient()) ) // Not a client ? (should never be true)
// continue;
if (client->pev->flags & FL_FROZEN)
client->EnableControl(TRUE);
else
client->EnableControl(FALSE);
}
/*
pActivator = UTIL_FindEntityByClassname(NULL, "player");
if (pActivator->pev->flags & FL_FROZEN)
((CBasePlayer *)((CBaseEntity *)pActivator))->EnableControl(TRUE);
else
((CBasePlayer *)((CBaseEntity *)pActivator))->EnableControl(FALSE);
*/
/*if (pActivator && pActivator->pev->flags & FL_CLIENT)
{
if (pActivator->pev->flags & FL_FROZEN)
{
// unfreeze him
((CBasePlayer *)((CBaseEntity *)pActivator))->EnableControl(TRUE);
m_hActivator = NULL;
SetThink( SUB_DoNothing );
}
else
{
// freeze him
((CBasePlayer *)((CBaseEntity *)pActivator))->EnableControl(FALSE);
if (m_flDelay)
{
m_hActivator = pActivator;
pev->nextthink = gpGlobals->time + m_flDelay;
}
}
}*/
}
void CPlayerFreeze::Think ( void )
{
Use(m_hActivator, this, USE_ON, 0);
}
LINK_ENTITY_TO_CLASS( trigger_playerfreeze, CPlayerFreeze );
//
// trigger_random
//
class CTriggerRandom : public CBaseDelay
{
public:
void KeyValue( KeyValueData *pkvd );
void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
private:
int m_iRandomRange;
float m_flProbability;
};
LINK_ENTITY_TO_CLASS( trigger_random, CTriggerRandom );
TYPEDESCRIPTION CTriggerRandom::m_SaveData[] =
{
DEFINE_FIELD( CTriggerRandom, m_iRandomRange, FIELD_INTEGER ),
DEFINE_FIELD( CTriggerRandom, m_flProbability, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE(CTriggerRandom,CBaseDelay);
void CTriggerRandom::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "randomrange"))
{
m_iRandomRange = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
} else
if (FStrEq(pkvd->szKeyName, "probability"))
{
m_flProbability = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
CBaseDelay::KeyValue( pkvd );
}
void CTriggerRandom::Spawn( void )
{
}
void CTriggerRandom::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
int FireId = RANDOM_LONG(0, m_iRandomRange-1); // was 1, m_iRandomRange
//SUB_UseTargets( this, USE_ON, 0 );
char m_iszFireTarget[60];
sprintf( m_iszFireTarget, "%s%d", STRING( pev->target ), FireId);
CBaseEntity *pEnt = NULL;
bool bFoundRandomTarget = false;
while ((pEnt = UTIL_FindEntityByTargetname( pEnt, m_iszFireTarget )) != NULL)
{
pEnt->Use( pActivator, pCaller, useType, value );
bFoundRandomTarget = true;
}
if ( !bFoundRandomTarget )
ALERT( at_console, "Randomly found entity `%s` not found!\n", m_iszFireTarget );
/*
CBaseEntity *pTarget = UTIL_FindEntityByTargetname( NULL, m_iszFireTarget );
if ( pTarget )
pTarget->Use( pActivator, pCaller, useType, value );
else
ALERT( at_console, "Randomly found entity %s not found!\n", m_iszFireTarget );
*/
//if ( pev->spawnflags & SF_RELAY_FIREONCE )
// UTIL_Remove( this );
}
//
// trigger_bit and trigger_bit_counter (used in ht11lasers)
//
typedef struct
{
bool Bits[8];
} TBitArray;
TBitArray ByteToArray(byte Number)
{
int i;
byte fl = 1;
TBitArray MyArr;
for (i = 0; i < 8; i++, fl = fl << 1) {
MyArr.Bits[i] = Number & fl;
}
return MyArr;
}
byte ArrayToByte(TBitArray A)
{
int i;
byte fl = 1;
byte Result;
for (i = 0; i < 8; i++, fl = fl << 1) {
if (A.Bits[i]) {
Result = Result | fl;
}
}
return Result;
}
class CTriggerBit : public CBaseDelay
{
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};
LINK_ENTITY_TO_CLASS( trigger_bit, CTriggerBit );
void CTriggerBit::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
SUB_UseTargets( this, USE_TOGGLE, 1.0 );
}
class CTriggerBitCounter : public CBaseDelay
{
public:
void KeyValue( KeyValueData *pkvd );
//void Spawn( void );
//void Precache( void );
void Think( void );
// use code, which will operates the bits
// use activators skin field as bit which we need to toggle
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
int m_iTriggerMask;
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
};
LINK_ENTITY_TO_CLASS( trigger_bit_counter, CTriggerBitCounter );
TYPEDESCRIPTION CTriggerBitCounter::m_SaveData[] =
{
DEFINE_FIELD( CTriggerBitCounter, m_iTriggerMask, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE(CTriggerBitCounter, CBaseDelay);
void CTriggerBitCounter::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "triggermask"))
{
m_iTriggerMask = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
CBaseDelay::KeyValue( pkvd );
}
void CTriggerBitCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
//uncommentme
//ALERT( at_console, "trigger_bit_counter used! bit id received %d\n", pActivator->pev->skin );
int m_iDesiredBit = pActivator->pev->skin;
ASSERT( m_iDesiredBit<=8 );
TBitArray MyArr = ByteToArray( pev->skin );
MyArr.Bits[m_iDesiredBit-1] = !MyArr.Bits[m_iDesiredBit-1];
pev->skin = ArrayToByte(MyArr);
if ( pev->skin == m_iTriggerMask )
{
ALERT( at_console, "trigger_bit_counter used! bit id received %d target %s\n", pActivator->pev->skin, STRING(pev->target) );
SUB_UseTargets( this, USE_ON, 0 );
}
}
void CTriggerBitCounter::Think( void )
{
/* if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON )
{
SUB_UseTargets( this, triggerType, 0 );
if ( pev->spawnflags & SF_AUTO_FIREONCE )
UTIL_Remove( this );
}
*/
}

View File

@ -75,6 +75,93 @@ void U_Srand( unsigned int seed )
glSeed = seed_table[seed & 0xff];
}
/*
=====================
UTIL_Intersect - moved here from controller.cpp and priest.cpp
=====================
*/
Vector UTIL_Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed )
{
Vector vecTo = vecDst - vecSrc;
float a = DotProduct( vecMove, vecMove ) - flSpeed * flSpeed;
float b = 0 * DotProduct(vecTo, vecMove); // why does this work?
float c = DotProduct( vecTo, vecTo );
float t;
if (a == 0)
{
t = c / (flSpeed * flSpeed);
}
else
{
t = b * b - 4 * a * c;
t = sqrt( t ) / (2.0 * a);
float t1 = -b +t;
float t2 = -b -t;
if (t1 < 0 || t2 < t1)
t = t2;
else
t = t1;
}
// ALERT( at_console, "Intersect %f\n", t );
if (t < 0.1)
t = 0.1;
if (t > 10.0)
t = 10.0;
Vector vecHit = vecTo + vecMove * t;
return vecHit.Normalize( ) * flSpeed;
}
void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity )
{
int i, j, k;
float distance;
float *minmaxs[2] = {mins, maxs};
TraceResult tmpTrace;
Vector vecHullEnd = tr.vecEndPos;
Vector vecEnd;
distance = 1e6f;
vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace );
if ( tmpTrace.flFraction < 1.0 )
{
tr = tmpTrace;
return;
}
for ( i = 0; i < 2; i++ )
{
for ( j = 0; j < 2; j++ )
{
for ( k = 0; k < 2; k++ )
{
vecEnd.x = vecHullEnd.x + minmaxs[i][0];
vecEnd.y = vecHullEnd.y + minmaxs[j][1];
vecEnd.z = vecHullEnd.z + minmaxs[k][2];
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace );
if ( tmpTrace.flFraction < 1.0 )
{
float thisDistance = (tmpTrace.vecEndPos - vecSrc).Length();
if ( thisDistance < distance )
{
tr = tmpTrace;
distance = thisDistance;
}
}
}
}
}
}
/*
=====================
UTIL_SharedRandomLong

View File

@ -408,6 +408,7 @@ extern DLL_GLOBAL const Vector g_vecZero;
#define AMBIENT_SOUND_LARGERADIUS 8
#define AMBIENT_SOUND_START_SILENT 16
#define AMBIENT_SOUND_NOT_LOOPING 32
#define AMBIENT_SHOWMESSAGE 512 // Decay: strings code
#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements

View File

@ -396,6 +396,7 @@ TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] =
DEFINE_FIELD( CBasePlayerItem, m_iId, FIELD_INTEGER ),
// DEFINE_FIELD( CBasePlayerItem, m_iIdPrimary, FIELD_INTEGER ),
// DEFINE_FIELD( CBasePlayerItem, m_iIdSecondary, FIELD_INTEGER ),
DEFINE_FIELD( CBasePlayerItem, DecayPlayerIndex, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE( CBasePlayerItem, CBaseAnimating )
@ -1228,6 +1229,7 @@ TYPEDESCRIPTION CWeaponBox::m_SaveData[] =
DEFINE_ARRAY( CWeaponBox, m_rgiszAmmo, FIELD_STRING, MAX_AMMO_SLOTS ),
DEFINE_ARRAY( CWeaponBox, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ),
DEFINE_FIELD( CWeaponBox, m_cAmmoTypes, FIELD_INTEGER ),
DEFINE_FIELD( CWeaponBox, m_iPlayerIndex, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity )
@ -1264,6 +1266,9 @@ void CWeaponBox::Spawn( void )
{
Precache();
if (!m_iPlayerIndex)
m_iPlayerIndex = 0;
pev->movetype = MOVETYPE_TOSS;
pev->solid = SOLID_TRIGGER;
@ -1334,6 +1339,13 @@ void CWeaponBox::Touch( CBaseEntity *pOther )
}
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
if (m_iPlayerIndex != 0)
{
if (pPlayer->m_iDecayId != this->m_iPlayerIndex)
return;
}
int i;
// dole out ammo

View File

@ -78,6 +78,8 @@ public:
#define WEAPON_TRIPMINE 13
#define WEAPON_SATCHEL 14
#define WEAPON_SNARK 15
#define WEAPON_DISPLACER 16
#define WEAPON_VORTI 17
#define WEAPON_ALLWEAPONS (~(1<<WEAPON_SUIT))
@ -149,6 +151,7 @@ public:
#define TRIPMINE_DEFAULT_GIVE 1
#define SNARK_DEFAULT_GIVE 5
#define HIVEHAND_DEFAULT_GIVE 8
#define DISPLACER_DEFAULT_GIVE 60
// The amount of ammo given to a player by an ammo item.
#define AMMO_URANIUMBOX_GIVE 20
@ -258,9 +261,12 @@ public:
CBasePlayer *m_pPlayer;
CBasePlayerItem *m_pNext;
int m_iId; // WEAPON_???
int DecayPlayerIndex;
virtual int iItemSlot( void ) { return 0; } // return 0 to MAX_ITEMS_SLOTS, used in hud
virtual void KeyValue( KeyValueData* pkvd); // to read player_index property
int iItemPosition( void ) { return ItemInfoArray[ m_iId ].iPosition; }
const char *pszAmmo1( void ) { return ItemInfoArray[ m_iId ].pszAmmo1; }
int iMaxAmmo1( void ) { return ItemInfoArray[ m_iId ].iMaxAmmo1; }
@ -448,6 +454,7 @@ public:
int m_rgAmmo[MAX_AMMO_SLOTS];// ammo quantities
int m_cAmmoTypes;// how many ammo types packed into this box (if packed by a level designer)
int m_iPlayerIndex; // Decay: player who can pickup this weaponbox 0 - both 1 - Gina 2 - Colette
};
#if CLIENT_DLL
@ -520,6 +527,49 @@ private:
unsigned short m_usCrowbar;
};
class CVortiHands : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 1; }
void EXPORT SwingAgain( void );
void EXPORT Smack( void );
int GetItemInfo(ItemInfo *p);
void PrimaryAttack( void );
void SecondaryAttack( void );
void WeaponIdle( void );
void StartFire( void );
void Fire( Vector vecOrigSrc, Vector vecDir, float flDamage );
float GetFullChargeTime( void );
int Swing( int fFirst );
BOOL Deploy( void );
void Holster( int skiplocal = 0 );
// was this weapon just fired primary or secondary?
// we need to know so we can pick the right set of effects.
BOOL m_fPrimaryFire;
int m_iSwing;
int m_iSoundState; // don't save this
TraceResult m_trHit;
virtual BOOL UseDecrement( void )
{
#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}
private:
unsigned short m_usVorti;
unsigned short m_usVortiFire;
unsigned short m_usVortiSpin;
};
class CPython : public CBasePlayerWeapon
{
public:

View File

@ -41,6 +41,8 @@ extern CBaseEntity *g_pLastSpawn;
DLL_GLOBAL edict_t *g_pBodyQueueHead;
CGlobalState gGlobalState;
extern DLL_GLOBAL int gDisplayTitle;
bool bDecay = false;
bool bSlaveCoop = false;
extern void W_Precache( void );
@ -477,6 +479,23 @@ void CWorld::Precache( void )
g_pGameRules = InstallGameRules();
if (bDecay)
{
if (m_bSlaveCoop) // if was initialized using KeyValue call
bSlaveCoop = m_bSlaveCoop;
else // otherwise NULL, thus no alien mode
bSlaveCoop = false;
CDecayRules *g_pDecayRules;
g_pDecayRules = (CDecayRules*)g_pGameRules;
g_pDecayRules->SetAlienMode( bSlaveCoop );
CBaseEntity *pEntity;
pEntity = CBaseEntity::Create( "trigger_autobot", g_vecZero, g_vecZero, edict() );
if ( !pEntity )
ALERT( at_aiconsole, "Autobot entity was not created!\n");
}
//!!!UNDONE why is there so much Spawn code in the Precache function? I'll just keep it here
///!!!LATER - do we want a sound ent in deathmatch? (sjb)
@ -713,6 +732,30 @@ void CWorld::KeyValue( KeyValueData *pkvd )
}
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "startsuit") )
{
if ( atoi(pkvd->szValue) )
{
g_startSuit = atoi(pkvd->szValue);
}
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "decay") )
{
if ( atoi(pkvd->szValue) )
{
bDecay = atoi(pkvd->szValue);
}
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "slavecoop") )
{
if ( atoi(pkvd->szValue) )
{
m_bSlaveCoop = atoi(pkvd->szValue);
}
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue( pkvd );
}

View File

@ -278,7 +278,6 @@ void CXenTree::Spawn( void )
SET_MODEL( ENT( pev ), "models/tree.mdl" );
pev->movetype = MOVETYPE_NONE;
pev->solid = SOLID_BBOX;
pev->takedamage = DAMAGE_YES;
UTIL_SetSize( pev, Vector( -30, -30, 0 ), Vector( 30, 30, 188 ) );

View File

@ -1969,6 +1969,15 @@ void PM_UnDuck( void )
newOrigin[i] += ( pmove->player_mins[1][i] - pmove->player_mins[0][i] );
}
}
*/
if ( pmove->onground != -1 && pmove->flags & FL_DUCKING && pmove->bInDuck == false)
{
for ( i = 0; i < 3; i++ )
{
newOrigin[i] += ( pmove->player_mins[1][i] - pmove->player_mins[0][i] );
}
}
trace = pmove->PM_PlayerTrace( newOrigin, newOrigin, PM_NORMAL, -1 );